Compare commits
No commits in common. "65b670d0dd5261aee9e866dcbff87ad436614f12" and "ace7a19dfa024c782c8f887fa9085f06e6cedcb7" have entirely different histories.
65b670d0dd
...
ace7a19dfa
@ -42,12 +42,10 @@ module.exports = {
|
||||
}
|
||||
],
|
||||
"import/order": ["error"],
|
||||
/**
|
||||
"indent": [
|
||||
"error",
|
||||
2
|
||||
],
|
||||
**/
|
||||
"linebreak-style": [
|
||||
"error",
|
||||
"unix"
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,4 +4,3 @@ node_modules
|
||||
/trees
|
||||
backup-tornado-*
|
||||
backup-tornadoInvoice-*
|
||||
backup-note-account-*
|
@ -6,7 +6,7 @@
|
||||
|
||||
Modern Toolsets for [Privacy Pools](https://www.forbes.com/sites/tomerniv/2023/09/07/privacy-pools-bridging-the-gap-between-blockchain-and-regulatory-compliance) on Ethereum
|
||||
|
||||
[](https://t.me/tornadoofficial) [](https://element.tornadocash.social) [](https://forum.tornado.ws/)
|
||||
[](https://t.me/tornadocli) [](https://element.tornadocash.social) [](https://forum.tornado.ws/)
|
||||
|
||||
</div>
|
||||
|
||||
|
356180
dist/cli.js
vendored
356180
dist/cli.js
vendored
File diff suppressed because one or more lines are too long
2649
dist/index.js
vendored
2649
dist/index.js
vendored
File diff suppressed because it is too large
Load Diff
2621
dist/index.mjs
vendored
2621
dist/index.mjs
vendored
File diff suppressed because it is too large
Load Diff
201496
dist/index.umd.js
vendored
201496
dist/index.umd.js
vendored
File diff suppressed because one or more lines are too long
9
dist/program.d.ts
vendored
9
dist/program.d.ts
vendored
@ -1,14 +1,13 @@
|
||||
import 'dotenv/config';
|
||||
import { Command } from 'commander';
|
||||
import { JsonRpcProvider, Provider, TransactionLike, Wallet, VoidSigner } from 'ethers';
|
||||
import { getProviderOptions, TornadoWallet, TornadoVoidSigner, Relayer, RelayerInfo, RelayerError, RelayerClient, fetchDataOptions, NetIdType, Config } from './services';
|
||||
import { JsonRpcProvider, Provider, TransactionLike, Wallet, VoidSigner, BigNumberish } from 'ethers';
|
||||
import { getProviderOptions, TornadoWallet, TornadoVoidSigner, Relayer, RelayerInfo, RelayerError, RelayerClient, fetchDataOptions, Config } from './services';
|
||||
export type commonProgramOptions = {
|
||||
rpc?: string;
|
||||
ethRpc?: string;
|
||||
graph?: string;
|
||||
ethGraph?: string;
|
||||
disableGraph?: boolean;
|
||||
accountKey?: string;
|
||||
relayer?: string;
|
||||
walletWithdrawal?: boolean;
|
||||
torPort?: number;
|
||||
@ -30,7 +29,7 @@ export declare function getProgramOptions(options: commonProgramOptions): Promis
|
||||
fetchDataOptions: fetchDataOptions;
|
||||
}>;
|
||||
export declare function getProgramGraphAPI(options: commonProgramOptions, config: Config): string;
|
||||
export declare function getProgramProvider(netId: NetIdType, rpcUrl: string | undefined, config: Config, providerOptions?: getProviderOptions): JsonRpcProvider;
|
||||
export declare function getProgramProvider(netId: BigNumberish, rpcUrl: string | undefined, config: Config, providerOptions?: getProviderOptions): JsonRpcProvider;
|
||||
export declare function getProgramSigner({ options, provider, }: {
|
||||
options: commonProgramOptions;
|
||||
provider: Provider;
|
||||
@ -38,7 +37,7 @@ export declare function getProgramSigner({ options, provider, }: {
|
||||
export declare function getProgramRelayer({ options, fetchDataOptions, netId, }: {
|
||||
options: commonProgramOptions;
|
||||
fetchDataOptions?: fetchDataOptions;
|
||||
netId: NetIdType;
|
||||
netId: number | string;
|
||||
}): Promise<{
|
||||
validRelayers?: RelayerInfo[] | Relayer[];
|
||||
invalidRelayers?: RelayerError[];
|
||||
|
6
dist/services/data.d.ts
vendored
6
dist/services/data.d.ts
vendored
@ -3,10 +3,10 @@ import { BaseEvents, MinimalEvents } from './events';
|
||||
export declare function existsAsync(fileOrDir: string): Promise<boolean>;
|
||||
export declare function zipAsync(file: AsyncZippable): Promise<Uint8Array>;
|
||||
export declare function unzipAsync(data: Uint8Array): Promise<Unzipped>;
|
||||
export declare function saveUserFile({ fileName, userDirectory, dataString, }: {
|
||||
fileName: string;
|
||||
export declare function saveEvents<T extends MinimalEvents>({ name, userDirectory, events, }: {
|
||||
name: string;
|
||||
userDirectory: string;
|
||||
dataString: string;
|
||||
events: T[];
|
||||
}): Promise<void>;
|
||||
export declare function loadSavedEvents<T extends MinimalEvents>({ name, userDirectory, deployedBlock, }: {
|
||||
name: string;
|
||||
|
9
dist/services/deposits.d.ts
vendored
9
dist/services/deposits.d.ts
vendored
@ -1,8 +1,7 @@
|
||||
import type { NetIdType } from './networkConfig';
|
||||
export type DepositType = {
|
||||
currency: string;
|
||||
amount: string;
|
||||
netId: NetIdType;
|
||||
netId: string | number;
|
||||
};
|
||||
export type createDepositParams = {
|
||||
nullifier: bigint;
|
||||
@ -35,7 +34,7 @@ export declare function createDeposit({ nullifier, secret }: createDepositParams
|
||||
export interface DepositConstructor {
|
||||
currency: string;
|
||||
amount: string;
|
||||
netId: NetIdType;
|
||||
netId: number;
|
||||
nullifier: bigint;
|
||||
secret: bigint;
|
||||
note: string;
|
||||
@ -47,7 +46,7 @@ export interface DepositConstructor {
|
||||
export declare class Deposit {
|
||||
currency: string;
|
||||
amount: string;
|
||||
netId: NetIdType;
|
||||
netId: number;
|
||||
nullifier: bigint;
|
||||
secret: bigint;
|
||||
note: string;
|
||||
@ -66,7 +65,7 @@ export type parsedInvoiceExec = DepositType & {
|
||||
export declare class Invoice {
|
||||
currency: string;
|
||||
amount: string;
|
||||
netId: NetIdType;
|
||||
netId: number;
|
||||
commitment: string;
|
||||
invoice: string;
|
||||
constructor(invoiceString: string);
|
||||
|
48
dist/services/encryptedNotes.d.ts
vendored
48
dist/services/encryptedNotes.d.ts
vendored
@ -1,48 +0,0 @@
|
||||
import { EthEncryptedData } from '@metamask/eth-sig-util';
|
||||
import { Echoer } from '@tornado/contracts';
|
||||
import { Wallet } from 'ethers';
|
||||
import { EchoEvents, EncryptedNotesEvents } from './events';
|
||||
import type { NetIdType } from './networkConfig';
|
||||
export interface NoteToEncrypt {
|
||||
address: string;
|
||||
noteHex: string;
|
||||
}
|
||||
export interface DecryptedNotes {
|
||||
blockNumber: number;
|
||||
address: string;
|
||||
noteHex: string;
|
||||
}
|
||||
export declare function packEncryptedMessage({ nonce, ephemPublicKey, ciphertext }: EthEncryptedData): string;
|
||||
export declare function unpackEncryptedMessage(encryptedMessage: string): EthEncryptedData & {
|
||||
messageBuff: string;
|
||||
};
|
||||
export interface NoteAccountConstructor {
|
||||
netId: NetIdType;
|
||||
blockNumber?: number;
|
||||
recoveryKey?: string;
|
||||
Echoer: Echoer;
|
||||
}
|
||||
export declare class NoteAccount {
|
||||
netId: NetIdType;
|
||||
blockNumber?: number;
|
||||
recoveryKey: string;
|
||||
recoveryAddress: string;
|
||||
recoveryPublicKey: string;
|
||||
Echoer: Echoer;
|
||||
constructor({ netId, blockNumber, recoveryKey, Echoer }: NoteAccountConstructor);
|
||||
/**
|
||||
* Intends to mock eth_getEncryptionPublicKey behavior from MetaMask
|
||||
* In order to make the recoveryKey retrival from Echoer possible from the bare private key
|
||||
*/
|
||||
static getWalletPublicKey(wallet: Wallet): string;
|
||||
getEncryptedAccount(walletPublicKey: string): {
|
||||
encryptedData: EthEncryptedData;
|
||||
data: string;
|
||||
};
|
||||
/**
|
||||
* Decrypt Echoer backuped note encryption account with private keys
|
||||
*/
|
||||
decryptAccountsWithWallet(wallet: Wallet, events: EchoEvents[]): NoteAccount[];
|
||||
decryptNotes(events: EncryptedNotesEvents[]): DecryptedNotes[];
|
||||
encryptNote({ address, noteHex }: NoteToEncrypt): string;
|
||||
}
|
43
dist/services/events/base.d.ts
vendored
43
dist/services/events/base.d.ts
vendored
@ -1,13 +1,12 @@
|
||||
import { BaseContract, Provider, EventLog, ContractEventName } from 'ethers';
|
||||
import type { Tornado, TornadoRouter, TornadoProxyLight, Governance, RelayerRegistry, Echoer } from '@tornado/contracts';
|
||||
import type { Tornado, TornadoRouter, TornadoProxyLight, Governance, RelayerRegistry } from '@tornado/contracts';
|
||||
import { BatchEventsService, BatchBlockService, BatchTransactionService, BatchEventOnProgress, BatchBlockOnProgress } from '../batch';
|
||||
import { fetchDataOptions } from '../providers';
|
||||
import type { NetIdType } from '../networkConfig';
|
||||
import type { BaseEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, AllGovernanceEvents, RegistersEvents, EchoEvents } from './types';
|
||||
import type { BaseEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, GovernanceProposalCreatedEvents, GovernanceVotedEvents, GovernanceDelegatedEvents, GovernanceUndelegatedEvents, RegistersEvents } from './types';
|
||||
export declare const DEPOSIT = "deposit";
|
||||
export declare const WITHDRAWAL = "withdrawal";
|
||||
export type BaseEventsServiceConstructor = {
|
||||
netId: NetIdType;
|
||||
netId: number | string;
|
||||
provider: Provider;
|
||||
graphApi?: string;
|
||||
subgraphName?: string;
|
||||
@ -29,7 +28,7 @@ export type BaseGraphParams = {
|
||||
onProgress?: BatchGraphOnProgress;
|
||||
};
|
||||
export declare class BaseEventsService<EventType extends MinimalEvents> {
|
||||
netId: NetIdType;
|
||||
netId: number | string;
|
||||
provider: Provider;
|
||||
graphApi?: string;
|
||||
subgraphName?: string;
|
||||
@ -82,7 +81,7 @@ export declare class BaseEventsService<EventType extends MinimalEvents> {
|
||||
}>;
|
||||
}
|
||||
export type BaseDepositsServiceConstructor = {
|
||||
netId: NetIdType;
|
||||
netId: number | string;
|
||||
provider: Provider;
|
||||
graphApi?: string;
|
||||
subgraphName?: string;
|
||||
@ -111,27 +110,8 @@ export declare class BaseDepositsService extends BaseEventsService<DepositsEvent
|
||||
events: (DepositsEvents | WithdrawalsEvents)[];
|
||||
}): void;
|
||||
}
|
||||
export type BaseEchoServiceConstructor = {
|
||||
netId: NetIdType;
|
||||
provider: Provider;
|
||||
graphApi?: string;
|
||||
subgraphName?: string;
|
||||
Echoer: Echoer;
|
||||
deployedBlock?: number;
|
||||
fetchDataOptions?: fetchDataOptions;
|
||||
};
|
||||
export declare class BaseEchoService extends BaseEventsService<EchoEvents> {
|
||||
constructor({ netId, provider, graphApi, subgraphName, Echoer, deployedBlock, fetchDataOptions, }: BaseEchoServiceConstructor);
|
||||
getInstanceName(): string;
|
||||
getType(): string;
|
||||
getGraphMethod(): string;
|
||||
formatEvents(events: EventLog[]): Promise<EchoEvents[]>;
|
||||
getEventsFromGraph({ fromBlock }: {
|
||||
fromBlock: number;
|
||||
}): Promise<BaseEvents<EchoEvents>>;
|
||||
}
|
||||
export type BaseEncryptedNotesServiceConstructor = {
|
||||
netId: NetIdType;
|
||||
netId: number | string;
|
||||
provider: Provider;
|
||||
graphApi?: string;
|
||||
subgraphName?: string;
|
||||
@ -146,8 +126,9 @@ export declare class BaseEncryptedNotesService extends BaseEventsService<Encrypt
|
||||
getGraphMethod(): string;
|
||||
formatEvents(events: EventLog[]): Promise<EncryptedNotesEvents[]>;
|
||||
}
|
||||
export type BaseGovernanceEventTypes = GovernanceProposalCreatedEvents | GovernanceVotedEvents | GovernanceDelegatedEvents | GovernanceUndelegatedEvents;
|
||||
export type BaseGovernanceServiceConstructor = {
|
||||
netId: NetIdType;
|
||||
netId: number | string;
|
||||
provider: Provider;
|
||||
graphApi?: string;
|
||||
subgraphName?: string;
|
||||
@ -155,19 +136,19 @@ export type BaseGovernanceServiceConstructor = {
|
||||
deployedBlock?: number;
|
||||
fetchDataOptions?: fetchDataOptions;
|
||||
};
|
||||
export declare class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents> {
|
||||
export declare class BaseGovernanceService extends BaseEventsService<BaseGovernanceEventTypes> {
|
||||
batchTransactionService: BatchTransactionService;
|
||||
constructor({ netId, provider, graphApi, subgraphName, Governance, deployedBlock, fetchDataOptions, }: BaseGovernanceServiceConstructor);
|
||||
getInstanceName(): string;
|
||||
getType(): string;
|
||||
getGraphMethod(): string;
|
||||
formatEvents(events: EventLog[]): Promise<AllGovernanceEvents[]>;
|
||||
formatEvents(events: EventLog[]): Promise<BaseGovernanceEventTypes[]>;
|
||||
getEventsFromGraph({ fromBlock }: {
|
||||
fromBlock: number;
|
||||
}): Promise<BaseEvents<AllGovernanceEvents>>;
|
||||
}): Promise<BaseEvents<BaseGovernanceEventTypes>>;
|
||||
}
|
||||
export type BaseRegistryServiceConstructor = {
|
||||
netId: NetIdType;
|
||||
netId: number | string;
|
||||
provider: Provider;
|
||||
graphApi?: string;
|
||||
subgraphName?: string;
|
||||
|
24
dist/services/events/node.d.ts
vendored
24
dist/services/events/node.d.ts
vendored
@ -1,6 +1,6 @@
|
||||
import { BatchBlockOnProgress, BatchEventOnProgress } from '../batch';
|
||||
import { BaseDepositsService, BaseEncryptedNotesService, BaseGovernanceService, BaseRegistryService, BaseDepositsServiceConstructor, BaseEncryptedNotesServiceConstructor, BaseGovernanceServiceConstructor, BaseRegistryServiceConstructor, BaseEchoServiceConstructor, BaseEchoService } from './base';
|
||||
import type { BaseEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, RegistersEvents, AllGovernanceEvents, EchoEvents } from './types';
|
||||
import { BaseDepositsService, BaseEncryptedNotesService, BaseGovernanceService, BaseRegistryService, BaseDepositsServiceConstructor, BaseEncryptedNotesServiceConstructor, BaseGovernanceServiceConstructor, BaseRegistryServiceConstructor, BaseGovernanceEventTypes } from './base';
|
||||
import type { BaseEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, RegistersEvents } from './types';
|
||||
export type NodeDepositsServiceConstructor = BaseDepositsServiceConstructor & {
|
||||
cacheDirectory?: string;
|
||||
userDirectory?: string;
|
||||
@ -17,20 +17,6 @@ export declare class NodeDepositsService extends BaseDepositsService {
|
||||
getEventsFromCache(): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>>;
|
||||
saveEvents({ events, lastBlock }: BaseEvents<DepositsEvents | WithdrawalsEvents>): Promise<void>;
|
||||
}
|
||||
export type NodeEchoServiceConstructor = BaseEchoServiceConstructor & {
|
||||
cacheDirectory?: string;
|
||||
userDirectory?: string;
|
||||
};
|
||||
export declare class NodeEchoService extends BaseEchoService {
|
||||
cacheDirectory?: string;
|
||||
userDirectory?: string;
|
||||
constructor({ netId, provider, graphApi, subgraphName, Echoer, deployedBlock, fetchDataOptions, cacheDirectory, userDirectory, }: NodeEchoServiceConstructor);
|
||||
updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
|
||||
updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
|
||||
getEventsFromDB(): Promise<BaseEvents<EchoEvents>>;
|
||||
getEventsFromCache(): Promise<BaseEvents<EchoEvents>>;
|
||||
saveEvents({ events, lastBlock }: BaseEvents<EchoEvents>): Promise<void>;
|
||||
}
|
||||
export type NodeEncryptedNotesServiceConstructor = BaseEncryptedNotesServiceConstructor & {
|
||||
cacheDirectory?: string;
|
||||
userDirectory?: string;
|
||||
@ -56,9 +42,9 @@ export declare class NodeGovernanceService extends BaseGovernanceService {
|
||||
updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
|
||||
updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
|
||||
updateTransactionProgress({ currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]): void;
|
||||
getEventsFromDB(): Promise<BaseEvents<AllGovernanceEvents>>;
|
||||
getEventsFromCache(): Promise<BaseEvents<AllGovernanceEvents>>;
|
||||
saveEvents({ events, lastBlock }: BaseEvents<AllGovernanceEvents>): Promise<void>;
|
||||
getEventsFromDB(): Promise<BaseEvents<BaseGovernanceEventTypes>>;
|
||||
getEventsFromCache(): Promise<BaseEvents<BaseGovernanceEventTypes>>;
|
||||
saveEvents({ events, lastBlock }: BaseEvents<BaseGovernanceEventTypes>): Promise<void>;
|
||||
}
|
||||
export type NodeRegistryServiceConstructor = BaseRegistryServiceConstructor & {
|
||||
cacheDirectory?: string;
|
||||
|
5
dist/services/events/types.d.ts
vendored
5
dist/services/events/types.d.ts
vendored
@ -39,7 +39,6 @@ export type GovernanceUndelegatedEvents = GovernanceEvents & {
|
||||
account: string;
|
||||
delegateFrom: string;
|
||||
};
|
||||
export type AllGovernanceEvents = GovernanceProposalCreatedEvents | GovernanceVotedEvents | GovernanceDelegatedEvents | GovernanceUndelegatedEvents;
|
||||
export type RegistersEvents = MinimalEvents & RelayerParams;
|
||||
export type DepositsEvents = MinimalEvents & {
|
||||
commitment: string;
|
||||
@ -53,10 +52,6 @@ export type WithdrawalsEvents = MinimalEvents & {
|
||||
fee: string;
|
||||
timestamp: number;
|
||||
};
|
||||
export type EchoEvents = MinimalEvents & {
|
||||
address: string;
|
||||
encryptedAccount: string;
|
||||
};
|
||||
export type EncryptedNotesEvents = MinimalEvents & {
|
||||
encryptedNote: string;
|
||||
};
|
||||
|
78
dist/services/graphql/index.d.ts
vendored
78
dist/services/graphql/index.d.ts
vendored
@ -1,5 +1,5 @@
|
||||
import { fetchDataOptions } from '../providers';
|
||||
import type { BaseGraphEvents, RegistersEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, BatchGraphOnProgress, EchoEvents, AllGovernanceEvents } from '../events';
|
||||
import type { BaseGraphEvents, RegistersEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, BatchGraphOnProgress } from '../events';
|
||||
export * from './queries';
|
||||
export type queryGraphParams = {
|
||||
graphApi: string;
|
||||
@ -165,29 +165,6 @@ export interface getNoteAccountsReturns {
|
||||
lastSyncBlock: null | number;
|
||||
}
|
||||
export declare function getNoteAccounts({ graphApi, subgraphName, address, fetchDataOptions, }: getNoteAccountsParams): Promise<getNoteAccountsReturns>;
|
||||
export interface GraphEchoEvents {
|
||||
noteAccounts: {
|
||||
id: string;
|
||||
blockNumber: string;
|
||||
address: string;
|
||||
encryptedAccount: string;
|
||||
}[];
|
||||
_meta: {
|
||||
block: {
|
||||
number: number;
|
||||
};
|
||||
hasIndexingErrors: boolean;
|
||||
};
|
||||
}
|
||||
export interface getGraphEchoEventsParams {
|
||||
graphApi: string;
|
||||
subgraphName: string;
|
||||
fromBlock: number;
|
||||
fetchDataOptions?: fetchDataOptions;
|
||||
onProgress?: BatchGraphOnProgress;
|
||||
}
|
||||
export declare function getGraphEchoEvents({ graphApi, subgraphName, fromBlock, fetchDataOptions, }: getGraphEchoEventsParams): Promise<GraphEchoEvents>;
|
||||
export declare function getAllGraphEchoEvents({ graphApi, subgraphName, fromBlock, fetchDataOptions, onProgress, }: getGraphEchoEventsParams): Promise<BaseGraphEvents<EchoEvents>>;
|
||||
export interface GraphEncryptedNotes {
|
||||
encryptedNotes: {
|
||||
blockNumber: string;
|
||||
@ -211,56 +188,3 @@ export interface getEncryptedNotesParams {
|
||||
}
|
||||
export declare function getEncryptedNotes({ graphApi, subgraphName, fromBlock, fetchDataOptions, }: getEncryptedNotesParams): Promise<GraphEncryptedNotes>;
|
||||
export declare function getAllEncryptedNotes({ graphApi, subgraphName, fromBlock, fetchDataOptions, onProgress, }: getEncryptedNotesParams): Promise<BaseGraphEvents<EncryptedNotesEvents>>;
|
||||
export interface GraphGovernanceEvents {
|
||||
proposals: {
|
||||
blockNumber: number;
|
||||
logIndex: number;
|
||||
transactionHash: string;
|
||||
proposalId: number;
|
||||
proposer: string;
|
||||
target: string;
|
||||
startTime: number;
|
||||
endTime: number;
|
||||
description: string;
|
||||
}[];
|
||||
votes: {
|
||||
blockNumber: number;
|
||||
logIndex: number;
|
||||
transactionHash: string;
|
||||
proposalId: number;
|
||||
voter: string;
|
||||
support: boolean;
|
||||
votes: string;
|
||||
from: string;
|
||||
input: string;
|
||||
}[];
|
||||
delegates: {
|
||||
blockNumber: number;
|
||||
logIndex: number;
|
||||
transactionHash: string;
|
||||
account: string;
|
||||
delegateTo: string;
|
||||
}[];
|
||||
undelegates: {
|
||||
blockNumber: number;
|
||||
logIndex: number;
|
||||
transactionHash: string;
|
||||
account: string;
|
||||
delegateFrom: string;
|
||||
}[];
|
||||
_meta: {
|
||||
block: {
|
||||
number: number;
|
||||
};
|
||||
hasIndexingErrors: boolean;
|
||||
};
|
||||
}
|
||||
export interface getGovernanceEventsParams {
|
||||
graphApi: string;
|
||||
subgraphName: string;
|
||||
fromBlock: number;
|
||||
fetchDataOptions?: fetchDataOptions;
|
||||
onProgress?: BatchGraphOnProgress;
|
||||
}
|
||||
export declare function getGovernanceEvents({ graphApi, subgraphName, fromBlock, fetchDataOptions, }: getGovernanceEventsParams): Promise<GraphGovernanceEvents>;
|
||||
export declare function getAllGovernanceEvents({ graphApi, subgraphName, fromBlock, fetchDataOptions, onProgress, }: getGovernanceEventsParams): Promise<BaseGraphEvents<AllGovernanceEvents>>;
|
||||
|
3
dist/services/graphql/queries.d.ts
vendored
3
dist/services/graphql/queries.d.ts
vendored
@ -4,7 +4,4 @@ export declare const GET_REGISTERED = "\n query getRegistered($first: Int, $fro
|
||||
export declare const GET_DEPOSITS = "\n query getDeposits($currency: String!, $amount: String!, $first: Int, $fromBlock: Int) {\n deposits(first: $first, orderBy: index, orderDirection: asc, where: { \n amount: $amount,\n currency: $currency,\n blockNumber_gte: $fromBlock\n }) {\n id\n blockNumber\n commitment\n index\n timestamp\n from\n }\n _meta {\n block {\n number\n }\n hasIndexingErrors\n }\n }\n";
|
||||
export declare const GET_WITHDRAWALS = "\n query getWithdrawals($currency: String!, $amount: String!, $first: Int, $fromBlock: Int!) {\n withdrawals(first: $first, orderBy: blockNumber, orderDirection: asc, where: { \n currency: $currency,\n amount: $amount,\n blockNumber_gte: $fromBlock\n }) {\n id\n blockNumber\n nullifier\n to\n fee\n timestamp\n }\n _meta {\n block {\n number\n }\n hasIndexingErrors\n }\n }\n";
|
||||
export declare const GET_NOTE_ACCOUNTS = "\n query getNoteAccount($address: String!) {\n noteAccounts(where: { address: $address }) {\n id\n index\n address\n encryptedAccount\n }\n _meta {\n block {\n number\n }\n hasIndexingErrors\n }\n }\n";
|
||||
export declare const GET_ECHO_EVENTS = "\n query getNoteAccounts($first: Int, $fromBlock: Int) {\n noteAccounts(first: $first, orderBy: blockNumber, orderDirection: asc, where: { blockNumber_gte: $fromBlock }) {\n id\n blockNumber\n address\n encryptedAccount\n }\n _meta {\n block {\n number\n }\n hasIndexingErrors\n }\n }\n";
|
||||
export declare const GET_ENCRYPTED_NOTES = "\n query getEncryptedNotes($first: Int, $fromBlock: Int) {\n encryptedNotes(first: $first, orderBy: blockNumber, orderDirection: asc, where: { blockNumber_gte: $fromBlock }) {\n blockNumber\n index\n transactionHash\n encryptedNote\n }\n _meta {\n block {\n number\n }\n hasIndexingErrors\n }\n }\n";
|
||||
export declare const GET_GOVERNANCE_EVENTS = "\n query getGovernanceEvents($first: Int, $fromBlock: Int) {\n proposals(first: $first, orderBy: blockNumber, orderDirection: asc, where: { blockNumber_gte: $fromBlock }) {\n blockNumber\n logIndex\n transactionHash\n proposalId\n proposer\n target\n startTime\n endTime\n description\n }\n votes(first: $first, orderBy: blockNumber, orderDirection: asc, where: { blockNumber_gte: $fromBlock }) {\n blockNumber\n logIndex\n transactionHash\n proposalId\n voter\n support\n votes\n from\n input\n }\n delegates(first: $first, orderBy: blockNumber, orderDirection: asc, where: { blockNumber_gte: $fromBlock }) {\n blockNumber\n logIndex\n transactionHash\n account\n delegateTo\n }\n undelegates(first: $first, orderBy: blockNumber, orderDirection: asc, where: { blockNumber_gte: $fromBlock }) {\n blockNumber\n logIndex\n transactionHash\n account\n delegateFrom\n }\n _meta {\n block {\n number\n }\n hasIndexingErrors\n }\n }\n";
|
||||
export declare const GET_GOVERNANCE_APY = "\n stakeDailyBurns(first: 30, orderBy: date, orderDirection: desc) {\n id\n date\n dailyAmountBurned\n }\n";
|
||||
|
2
dist/services/index.d.ts
vendored
2
dist/services/index.d.ts
vendored
@ -4,7 +4,6 @@ export * from './schemas';
|
||||
export * from './batch';
|
||||
export * from './data';
|
||||
export * from './deposits';
|
||||
export * from './encryptedNotes';
|
||||
export * from './fees';
|
||||
export * from './merkleTree';
|
||||
export * from './mimc';
|
||||
@ -16,6 +15,5 @@ export * from './prices';
|
||||
export * from './providers';
|
||||
export * from './relayerClient';
|
||||
export * from './tokens';
|
||||
export * from './treeCache';
|
||||
export * from './utils';
|
||||
export * from './websnark';
|
||||
|
23
dist/services/merkleTree.d.ts
vendored
23
dist/services/merkleTree.d.ts
vendored
@ -1,11 +1,10 @@
|
||||
import { MerkleTree, PartialMerkleTree, Element, TreeEdge } from '@tornado/fixed-merkle-tree';
|
||||
import { MerkleTree, Element } from '@tornado/fixed-merkle-tree';
|
||||
import type { Tornado } from '@tornado/contracts';
|
||||
import type { DepositType } from './deposits';
|
||||
import type { DepositsEvents } from './events';
|
||||
import type { NetIdType } from './networkConfig';
|
||||
export type MerkleTreeConstructor = DepositType & {
|
||||
Tornado: Tornado;
|
||||
commitmentHex?: string;
|
||||
commitment?: string;
|
||||
merkleTreeHeight?: number;
|
||||
emptyElement?: string;
|
||||
merkleWorkerPath?: string;
|
||||
@ -13,18 +12,18 @@ export type MerkleTreeConstructor = DepositType & {
|
||||
export declare class MerkleTreeService {
|
||||
currency: string;
|
||||
amount: string;
|
||||
netId: NetIdType;
|
||||
netId: number;
|
||||
Tornado: Tornado;
|
||||
commitmentHex?: string;
|
||||
commitment?: string;
|
||||
instanceName: string;
|
||||
merkleTreeHeight: number;
|
||||
emptyElement: string;
|
||||
merkleWorkerPath?: string;
|
||||
constructor({ netId, amount, currency, Tornado, commitmentHex, merkleTreeHeight, emptyElement, merkleWorkerPath, }: MerkleTreeConstructor);
|
||||
createTree(events: Element[]): Promise<MerkleTree>;
|
||||
createPartialTree({ edge, elements }: {
|
||||
edge: TreeEdge;
|
||||
elements: Element[];
|
||||
}): Promise<PartialMerkleTree>;
|
||||
verifyTree(events: DepositsEvents[]): Promise<MerkleTree>;
|
||||
constructor({ netId, amount, currency, Tornado, commitment, merkleTreeHeight, emptyElement, merkleWorkerPath, }: MerkleTreeConstructor);
|
||||
createTree({ events }: {
|
||||
events: Element[];
|
||||
}): Promise<MerkleTree>;
|
||||
verifyTree({ events }: {
|
||||
events: DepositsEvents[];
|
||||
}): Promise<MerkleTree>;
|
||||
}
|
||||
|
66
dist/services/networkConfig.d.ts
vendored
66
dist/services/networkConfig.d.ts
vendored
@ -1,17 +1,3 @@
|
||||
/**
|
||||
* Type of default supported networks
|
||||
*/
|
||||
export declare enum NetId {
|
||||
MAINNET = 1,
|
||||
BSC = 56,
|
||||
POLYGON = 137,
|
||||
OPTIMISM = 10,
|
||||
ARBITRUM = 42161,
|
||||
GNOSIS = 100,
|
||||
AVALANCHE = 43114,
|
||||
SEPOLIA = 11155111
|
||||
}
|
||||
export type NetIdType = NetId | number;
|
||||
export interface RpcUrl {
|
||||
name: string;
|
||||
url: string;
|
||||
@ -51,20 +37,20 @@ export type Config = {
|
||||
};
|
||||
nativeCurrency: string;
|
||||
currencyName: string;
|
||||
explorerUrl: string;
|
||||
explorerUrl: {
|
||||
tx: string;
|
||||
address: string;
|
||||
block: string;
|
||||
};
|
||||
merkleTreeHeight: number;
|
||||
emptyElement: string;
|
||||
networkName: string;
|
||||
deployedBlock: number;
|
||||
rpcUrls: RpcUrls;
|
||||
multicallContract: string;
|
||||
multicall: string;
|
||||
routerContract: string;
|
||||
echoContract: string;
|
||||
offchainOracleContract?: string;
|
||||
tornContract?: string;
|
||||
governanceContract?: string;
|
||||
stakingRewardsContract?: string;
|
||||
registryContract?: string;
|
||||
echoContract: string;
|
||||
aggregatorContract?: string;
|
||||
reverseRecordsContract?: string;
|
||||
gasPriceOracleContract?: string;
|
||||
@ -72,7 +58,6 @@ export type Config = {
|
||||
ovmGasPriceOracleContract?: string;
|
||||
tornadoSubgraph: string;
|
||||
registrySubgraph?: string;
|
||||
governanceSubgraph?: string;
|
||||
subgraphs: SubgraphUrls;
|
||||
tokens: TokenInstances;
|
||||
optionalTokens?: string[];
|
||||
@ -85,32 +70,17 @@ export type Config = {
|
||||
REGISTRY_BLOCK?: number;
|
||||
MINING_BLOCK_TIME?: number;
|
||||
};
|
||||
'torn.contract.tornadocash.eth'?: string;
|
||||
'governance.contract.tornadocash.eth'?: string;
|
||||
'staking-rewards.contract.tornadocash.eth'?: string;
|
||||
'tornado-router.contract.tornadocash.eth'?: string;
|
||||
'tornado-proxy-light.contract.tornadocash.eth'?: string;
|
||||
};
|
||||
export type networkConfig = {
|
||||
[key in NetIdType]: Config;
|
||||
[key in string]: Config;
|
||||
};
|
||||
export declare const defaultConfig: networkConfig;
|
||||
export declare const enabledChains: number[];
|
||||
/**
|
||||
* Custom config object to extend default config
|
||||
*
|
||||
* Inspired by getUrlFunc from ethers.js
|
||||
* https://github.com/ethers-io/ethers.js/blob/v6/src.ts/utils/fetch.ts#L59
|
||||
*/
|
||||
export declare let customConfig: networkConfig;
|
||||
/**
|
||||
* Add or override existing network config object
|
||||
*
|
||||
* Could be also called on the UI hook so that the UI could allow people to use custom privacy pools
|
||||
*/
|
||||
export declare function addNetwork(newConfig: networkConfig): void;
|
||||
export declare function getNetworkConfig(): networkConfig;
|
||||
export declare function getConfig(netId: NetIdType): Config;
|
||||
export declare function getInstanceByAddress({ netId, address }: {
|
||||
netId: NetIdType;
|
||||
address: string;
|
||||
}): {
|
||||
amount: string;
|
||||
currency: string;
|
||||
} | undefined;
|
||||
export declare function getSubdomains(): string[];
|
||||
export declare const blockSyncInterval = 10000;
|
||||
export declare const enabledChains: string[];
|
||||
export declare const networkConfig: networkConfig;
|
||||
export declare const subdomains: string[];
|
||||
export default networkConfig;
|
||||
|
4
dist/services/parser.d.ts
vendored
4
dist/services/parser.d.ts
vendored
@ -4,7 +4,3 @@ export declare function parseRelayer(value?: string): string;
|
||||
export declare function parseAddress(value?: string): string;
|
||||
export declare function parseMnemonic(value?: string): string;
|
||||
export declare function parseKey(value?: string): string;
|
||||
/**
|
||||
* Recovery key shouldn't have a 0x prefix (Also this is how the UI generates)
|
||||
*/
|
||||
export declare function parseRecoveryKey(value?: string): string;
|
||||
|
8
dist/services/providers.d.ts
vendored
8
dist/services/providers.d.ts
vendored
@ -3,9 +3,9 @@
|
||||
/// <reference types="node" />
|
||||
import type { EventEmitter } from 'stream';
|
||||
import type { RequestOptions } from 'http';
|
||||
import { JsonRpcApiProvider, JsonRpcProvider, Wallet, FetchGetUrlFunc, Provider, SigningKey, TransactionRequest, JsonRpcSigner, BrowserProvider, Networkish, Eip1193Provider, VoidSigner, FetchUrlFeeDataNetworkPlugin } from 'ethers';
|
||||
import { JsonRpcApiProvider, JsonRpcProvider, Wallet, FetchGetUrlFunc, Provider, SigningKey, TransactionRequest, JsonRpcSigner, BrowserProvider, Networkish, Eip1193Provider, VoidSigner, FetchUrlFeeDataNetworkPlugin, BigNumberish } from 'ethers';
|
||||
import type { RequestInfo, RequestInit, Response, HeadersInit } from 'node-fetch';
|
||||
import type { Config, NetIdType } from './networkConfig';
|
||||
import type { Config } from './networkConfig';
|
||||
declare global {
|
||||
interface Window {
|
||||
ethereum?: Eip1193Provider & EventEmitter;
|
||||
@ -41,7 +41,7 @@ export type getProviderOptions = fetchDataOptions & {
|
||||
};
|
||||
export declare function getGasOraclePlugin(networkKey: string, fetchOptions?: getProviderOptions): FetchUrlFeeDataNetworkPlugin;
|
||||
export declare function getProvider(rpcUrl: string, fetchOptions?: getProviderOptions): Promise<JsonRpcProvider>;
|
||||
export declare function getProviderWithNetId(netId: NetIdType, rpcUrl: string, config: Config, fetchOptions?: getProviderOptions): JsonRpcProvider;
|
||||
export declare function getProviderWithNetId(netId: BigNumberish, rpcUrl: string, config: Config, fetchOptions?: getProviderOptions): JsonRpcProvider;
|
||||
export declare const populateTransaction: (signer: TornadoWallet | TornadoVoidSigner | TornadoRpcSigner, tx: TransactionRequest) => Promise<TransactionRequest>;
|
||||
export type TornadoWalletOptions = {
|
||||
gasPriceBump?: number;
|
||||
@ -80,7 +80,7 @@ export declare class TornadoRpcSigner extends JsonRpcSigner {
|
||||
export type connectWalletFunc = (...args: any[]) => Promise<void>;
|
||||
export type handleWalletFunc = (...args: any[]) => void;
|
||||
export type TornadoBrowserProviderOptions = TornadoWalletOptions & {
|
||||
webChainId?: NetIdType;
|
||||
webChainId?: BigNumberish;
|
||||
connectWallet?: connectWalletFunc;
|
||||
handleNetworkChanges?: handleWalletFunc;
|
||||
handleAccountChanges?: handleWalletFunc;
|
||||
|
32
dist/services/relayerClient.d.ts
vendored
32
dist/services/relayerClient.d.ts
vendored
@ -1,6 +1,6 @@
|
||||
import type { Aggregator } from '@tornado/contracts';
|
||||
import type { RelayerStructOutput } from '@tornado/contracts/dist/contracts/Governance/Aggregator/Aggregator';
|
||||
import { NetIdType, Config } from './networkConfig';
|
||||
import type { Config } from './networkConfig';
|
||||
import { fetchDataOptions } from './providers';
|
||||
import type { snarkProofs } from './websnark';
|
||||
export declare const MIN_STAKE_BALANCE: bigint;
|
||||
@ -9,22 +9,20 @@ export interface RelayerParams {
|
||||
relayerAddress?: string;
|
||||
}
|
||||
export interface Relayer {
|
||||
netId: NetIdType;
|
||||
netId: number;
|
||||
url: string;
|
||||
hostname: string;
|
||||
rewardAccount: string;
|
||||
instances: string[];
|
||||
gasPrice?: number;
|
||||
ethPrices?: {
|
||||
[key in string]: string;
|
||||
};
|
||||
currentQueue: number;
|
||||
tornadoServiceFee: number;
|
||||
}
|
||||
export type RelayerInfo = Relayer & {
|
||||
hostname: string;
|
||||
ensName: string;
|
||||
stakeBalance: bigint;
|
||||
relayerAddress: string;
|
||||
ethPrices?: {
|
||||
[key in string]: string;
|
||||
};
|
||||
};
|
||||
export type RelayerError = {
|
||||
hostname: string;
|
||||
@ -48,7 +46,7 @@ export interface RelayerStatus {
|
||||
fast: number;
|
||||
additionalProperties?: number;
|
||||
};
|
||||
netId: NetIdType;
|
||||
netId: number;
|
||||
ethPrices?: {
|
||||
[key in string]: string;
|
||||
};
|
||||
@ -86,20 +84,12 @@ export interface semanticVersion {
|
||||
buildmetadata?: string;
|
||||
}
|
||||
export declare function parseSemanticVersion(version: string): semanticVersion;
|
||||
export declare function isRelayerUpdated(relayerVersion: string, netId: NetIdType): boolean;
|
||||
export declare function isRelayerUpdated(relayerVersion: string, netId: number | string): boolean;
|
||||
export declare function calculateScore({ stakeBalance, tornadoServiceFee }: RelayerInfo, minFee?: number, maxFee?: number): bigint;
|
||||
export declare function getWeightRandom(weightsScores: bigint[], random: bigint): number;
|
||||
export type RelayerInstanceList = {
|
||||
[key in string]: {
|
||||
instanceAddress: {
|
||||
[key in string]: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
export declare function getSupportedInstances(instanceList: RelayerInstanceList): string[];
|
||||
export declare function pickWeightedRandomRelayer(relayers: RelayerInfo[], netId: NetIdType): RelayerInfo;
|
||||
export declare function pickWeightedRandomRelayer(relayers: RelayerInfo[], netId: string | number): RelayerInfo;
|
||||
export interface RelayerClientConstructor {
|
||||
netId: NetIdType;
|
||||
netId: number | string;
|
||||
config: Config;
|
||||
Aggregator: Aggregator;
|
||||
fetchDataOptions?: fetchDataOptions;
|
||||
@ -108,7 +98,7 @@ export type RelayerClientWithdraw = snarkProofs & {
|
||||
contract: string;
|
||||
};
|
||||
export declare class RelayerClient {
|
||||
netId: NetIdType;
|
||||
netId: number;
|
||||
config: Config;
|
||||
Aggregator: Aggregator;
|
||||
selectedRelayer?: Relayer;
|
||||
|
4
dist/services/schemas/status.d.ts
vendored
4
dist/services/schemas/status.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
import { Config, NetIdType } from '../networkConfig';
|
||||
import type { Config } from '../networkConfig';
|
||||
export type statusInstanceType = {
|
||||
type: string;
|
||||
properties: {
|
||||
@ -88,5 +88,5 @@ declare const bnType: {
|
||||
type: string;
|
||||
BN: boolean;
|
||||
};
|
||||
export declare function getStatusSchema(netId: NetIdType, config: Config): statusSchema;
|
||||
export declare function getStatusSchema(netId: number | string, config: Config): statusSchema;
|
||||
export {};
|
||||
|
35
dist/services/treeCache.d.ts
vendored
35
dist/services/treeCache.d.ts
vendored
@ -1,35 +0,0 @@
|
||||
/**
|
||||
* Create tree cache file from node.js
|
||||
*
|
||||
* Only works for node.js, modified from https://github.com/tornadocash/tornado-classic-ui/blob/master/scripts/updateTree.js
|
||||
*/
|
||||
import { MerkleTree } from '@tornado/fixed-merkle-tree';
|
||||
import { DepositsEvents } from './events';
|
||||
import type { NetIdType } from './networkConfig';
|
||||
export interface TreeCacheConstructor {
|
||||
netId: NetIdType;
|
||||
amount: string;
|
||||
currency: string;
|
||||
userDirectory: string;
|
||||
PARTS_COUNT?: number;
|
||||
LEAVES?: number;
|
||||
zeroElement?: string;
|
||||
}
|
||||
export interface treeMetadata {
|
||||
blockNumber: number;
|
||||
logIndex: number;
|
||||
transactionHash: string;
|
||||
timestamp: number;
|
||||
from: string;
|
||||
leafIndex: number;
|
||||
}
|
||||
export declare class TreeCache {
|
||||
netId: NetIdType;
|
||||
amount: string;
|
||||
currency: string;
|
||||
userDirectory: string;
|
||||
PARTS_COUNT: number;
|
||||
constructor({ netId, amount, currency, userDirectory, PARTS_COUNT }: TreeCacheConstructor);
|
||||
getInstanceName(): string;
|
||||
createTree(events: DepositsEvents[], tree: MerkleTree): Promise<void>;
|
||||
}
|
5
dist/services/utils.d.ts
vendored
5
dist/services/utils.d.ts
vendored
@ -1,20 +1,15 @@
|
||||
/// <reference types="node" />
|
||||
/// <reference types="node" />
|
||||
import { webcrypto } from 'crypto';
|
||||
import BN from 'bn.js';
|
||||
import type { BigNumberish } from 'ethers';
|
||||
type bnInput = number | string | number[] | Uint8Array | Buffer | BN;
|
||||
export declare const isNode: boolean;
|
||||
export declare const crypto: webcrypto.Crypto;
|
||||
export declare const chunk: <T>(arr: T[], size: number) => T[][];
|
||||
export declare function sleep(ms: number): Promise<unknown>;
|
||||
export declare function validateUrl(url: string, protocols?: string[]): boolean;
|
||||
export declare function concatBytes(...arrays: Uint8Array[]): Uint8Array;
|
||||
export declare function bufferToBytes(b: Buffer): Uint8Array;
|
||||
export declare function bytesToBase64(bytes: Uint8Array): string;
|
||||
export declare function base64ToBytes(base64: string): Uint8Array;
|
||||
export declare function bytesToHex(bytes: Uint8Array): string;
|
||||
export declare function hexToBytes(hexString: string): Uint8Array;
|
||||
export declare function bytesToBN(bytes: Uint8Array): bigint;
|
||||
export declare function bnToBytes(bigint: bigint | string): Uint8Array;
|
||||
export declare function leBuff2Int(bytes: Uint8Array): BN;
|
||||
|
38
package.json
38
package.json
@ -1,12 +1,10 @@
|
||||
{
|
||||
"name": "tornado-cli",
|
||||
"version": "1.0.3-alpha",
|
||||
"version": "1.0.1-alpha",
|
||||
"description": "Modern Toolsets for Privacy Pools on Ethereum",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"unpkg": "./dist/index.umd.js",
|
||||
"jsdelivr": "./dist/index.umd.js",
|
||||
"bin": {
|
||||
"tornado-cli": "./dist/cli.js"
|
||||
},
|
||||
@ -14,9 +12,7 @@
|
||||
"typechain": "typechain --target ethers-v6 --out-dir src/typechain src/abi/*.json",
|
||||
"types": "tsc --declaration --emitDeclarationOnly",
|
||||
"lint": "eslint src/**/*.ts --ext .ts --ignore-pattern src/typechain",
|
||||
"build:node": "ts-node scripts/fflate.ts && rollup -c",
|
||||
"build:web": "webpack",
|
||||
"build": "yarn types && yarn build:node && yarn build:web",
|
||||
"build": "yarn types && rollup -c",
|
||||
"start": "ts-node src/cli.ts",
|
||||
"startHelp": "ts-node src/cli.ts help",
|
||||
"createDeposit": "ts-node src/cli.ts create",
|
||||
@ -24,10 +20,8 @@
|
||||
"depositInvoice": "ts-node src/cli.ts depositInvoice",
|
||||
"withdraw": "ts-node src/cli.ts withdraw",
|
||||
"compliance": "ts-node src/cli.ts compliance",
|
||||
"updateEvents": "ts-node src/cli.ts updateEvents",
|
||||
"syncEvents": "ts-node src/cli.ts syncEvents",
|
||||
"relayers": "ts-node src/cli.ts relayers",
|
||||
"createAccount": "ts-node src/cli.ts createAccount",
|
||||
"decryptNotes": "ts-node src/cli.ts decryptNotes",
|
||||
"send": "ts-node src/cli.ts send",
|
||||
"balance": "ts-node src/cli.ts balance",
|
||||
"sign": "ts-node src/cli.ts sign",
|
||||
@ -52,24 +46,23 @@
|
||||
"yarn.lock"
|
||||
],
|
||||
"dependencies": {
|
||||
"@metamask/eth-sig-util": "^7.0.1",
|
||||
"@colors/colors": "1.5.0",
|
||||
"@tornado/contracts": "1.0.0",
|
||||
"@tornado/fixed-merkle-tree": "0.7.3",
|
||||
"@tornado/snarkjs": "0.1.20",
|
||||
"@tornado/websnark": "0.0.4",
|
||||
"ajv": "^8.12.0",
|
||||
"bloomfilter.js": "^1.0.2",
|
||||
"bignumber.js": "^9.1.2",
|
||||
"bn.js": "^5.2.1",
|
||||
"circomlibjs": "0.1.7",
|
||||
"cross-fetch": "^4.0.0",
|
||||
"ethers": "^6.12.0",
|
||||
"ffjavascript": "0.2.48",
|
||||
"fflate": "^0.8.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@colors/colors": "1.5.0",
|
||||
"cli-table3": "^0.6.4",
|
||||
"commander": "^12.0.0",
|
||||
"cross-fetch": "^4.0.0",
|
||||
"dotenv": "^16.4.5",
|
||||
"ethers": "^6.12.0",
|
||||
"ffjavascript": "0.2.48",
|
||||
"fflate": "^0.8.2",
|
||||
"figlet": "^1.7.0",
|
||||
"http-proxy-agent": "^7.0.2",
|
||||
"https-proxy-agent": "^7.0.4",
|
||||
"moment": "^2.30.1",
|
||||
@ -79,6 +72,7 @@
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@rollup/plugin-replace": "^5.0.5",
|
||||
"@typechain/ethers-v6": "^0.5.1",
|
||||
"@types/bn.js": "^5.1.5",
|
||||
"@types/circomlibjs": "^0.1.6",
|
||||
@ -87,24 +81,18 @@
|
||||
"@types/node-fetch": "^2.6.11",
|
||||
"@typescript-eslint/eslint-plugin": "^7.6.0",
|
||||
"@typescript-eslint/parser": "^7.6.0",
|
||||
"dotenv": "^16.4.5",
|
||||
"esbuild": "^0.20.2",
|
||||
"esbuild-loader": "^4.1.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.1",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"figlet": "^1.7.0",
|
||||
"node-polyfill-webpack-plugin": "^3.0.0",
|
||||
"prettier": "^3.2.5",
|
||||
"rollup": "^4.14.1",
|
||||
"rollup-plugin-esbuild": "^6.1.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsc": "^2.0.4",
|
||||
"typechain": "^8.3.2",
|
||||
"typescript": "^5.4.4",
|
||||
"webpack": "^5.91.0",
|
||||
"webpack-cli": "^5.1.4"
|
||||
"typescript": "^5.4.4"
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,13 @@ import esbuild from 'rollup-plugin-esbuild';
|
||||
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import json from '@rollup/plugin-json';
|
||||
import replace from '@rollup/plugin-replace';
|
||||
import pkgJson from './package.json' assert { type: 'json' };
|
||||
|
||||
const external = Object.keys(pkgJson.dependencies).concat(
|
||||
Object.keys(pkgJson.optionalDependencies),
|
||||
[
|
||||
const external = Object.keys(pkgJson.dependencies).concat(...[
|
||||
'@tornado/websnark/src/utils',
|
||||
'@tornado/websnark/src/groth16',
|
||||
]
|
||||
);
|
||||
]);
|
||||
|
||||
const config = [
|
||||
{
|
||||
@ -30,8 +28,8 @@ const config = [
|
||||
sourceMap: true,
|
||||
target: 'es2016',
|
||||
}),
|
||||
commonjs(),
|
||||
nodeResolve(),
|
||||
commonjs(),
|
||||
json()
|
||||
],
|
||||
},
|
||||
@ -55,6 +53,28 @@ const config = [
|
||||
json()
|
||||
],
|
||||
},
|
||||
{
|
||||
input: 'src/cli.ts',
|
||||
output: [
|
||||
{
|
||||
file: pkgJson.bin[pkgJson.name],
|
||||
format: "cjs",
|
||||
esModule: false,
|
||||
banner: '#!/usr/bin/env node\n'
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
esbuild({
|
||||
include: /\.[jt]sx?$/,
|
||||
minify: false,
|
||||
sourceMap: true,
|
||||
target: 'es2016',
|
||||
}),
|
||||
nodeResolve(),
|
||||
commonjs(),
|
||||
json()
|
||||
],
|
||||
},
|
||||
{
|
||||
input: 'src/merkleTreeWorker.ts',
|
||||
output: [
|
||||
@ -72,10 +92,36 @@ const config = [
|
||||
sourceMap: true,
|
||||
target: 'es2016',
|
||||
}),
|
||||
commonjs(),
|
||||
nodeResolve(),
|
||||
commonjs(),
|
||||
json()
|
||||
],
|
||||
},
|
||||
{
|
||||
input: 'src/merkleTreeWorker.ts',
|
||||
output: [
|
||||
{
|
||||
file: 'static/merkleTreeWorker.umd.js',
|
||||
format: "umd",
|
||||
esModule: false
|
||||
},
|
||||
],
|
||||
treeshake: 'smallest',
|
||||
external: ['web-worker'],
|
||||
plugins: [
|
||||
esbuild({
|
||||
include: /\.[jt]sx?$/,
|
||||
minify: false,
|
||||
sourceMap: true,
|
||||
target: 'es2016',
|
||||
}),
|
||||
nodeResolve(),
|
||||
commonjs(),
|
||||
json(),
|
||||
replace({
|
||||
'process.browser': 'true'
|
||||
})
|
||||
],
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -1,39 +0,0 @@
|
||||
/**
|
||||
* Correct the resolve field of fflate as we don't use browser esm
|
||||
*
|
||||
* See issue https://github.com/101arrowz/fflate/issues/211
|
||||
*/
|
||||
import fs from 'fs';
|
||||
|
||||
const pkgJson = JSON.parse(fs.readFileSync('./node_modules/fflate/package.json', { encoding: 'utf8' }));
|
||||
const backupJson = JSON.stringify(pkgJson, null, 2);
|
||||
|
||||
let changes = false
|
||||
|
||||
if (pkgJson.module.includes('browser')) {
|
||||
pkgJson.module = './esm/index.mjs';
|
||||
|
||||
changes = true;
|
||||
}
|
||||
|
||||
if (pkgJson.exports['.']?.import?.types && pkgJson.exports?.['.']?.import?.types.includes('browser')) {
|
||||
pkgJson.exports['.'] = {
|
||||
...pkgJson.exports['.'],
|
||||
"import": {
|
||||
"types": "./esm/index.d.mts",
|
||||
"default": "./esm/index.mjs"
|
||||
},
|
||||
"require": {
|
||||
"types": "./lib/index.d.ts",
|
||||
"default": "./lib/index.cjs"
|
||||
}
|
||||
}
|
||||
|
||||
changes = true;
|
||||
}
|
||||
|
||||
|
||||
if (changes) {
|
||||
fs.writeFileSync('./node_modules/fflate/package.backup.json', backupJson + '\n');
|
||||
fs.writeFileSync('./node_modules/fflate/package.json', JSON.stringify(pkgJson, null, 2) + '\n');
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any, prettier/prettier */
|
||||
import workerThreads from 'worker_threads';
|
||||
import { MerkleTree, Element, TreeEdge, PartialMerkleTree } from '@tornado/fixed-merkle-tree';
|
||||
import { mimc, isNode } from './services';
|
||||
@ -65,5 +65,5 @@ if (isNode && workerThreads) {
|
||||
postMessage(merkleTree.toString());
|
||||
});
|
||||
} else {
|
||||
throw new Error('This browser / environment does not support workers!');
|
||||
throw new Error('This browser / environment doesn\'t support workers!');
|
||||
}
|
||||
|
462
src/program.ts
462
src/program.ts
@ -13,7 +13,6 @@ import {
|
||||
RelayerRegistry__factory,
|
||||
Aggregator__factory,
|
||||
Governance__factory,
|
||||
Echoer__factory,
|
||||
} from '@tornado/contracts';
|
||||
import {
|
||||
JsonRpcProvider,
|
||||
@ -28,7 +27,7 @@ import {
|
||||
ZeroAddress,
|
||||
MaxUint256,
|
||||
Transaction,
|
||||
getAddress,
|
||||
BigNumberish,
|
||||
} from 'ethers';
|
||||
import type MerkleTree from '@tornado/fixed-merkle-tree';
|
||||
import * as packageJson from '../package.json';
|
||||
@ -63,7 +62,6 @@ import {
|
||||
TornadoFeeOracle,
|
||||
TokenPriceOracle,
|
||||
calculateSnarkProof,
|
||||
NodeEchoService,
|
||||
NodeEncryptedNotesService,
|
||||
NodeGovernanceService,
|
||||
RelayerClient,
|
||||
@ -72,34 +70,27 @@ import {
|
||||
Invoice,
|
||||
fetchData,
|
||||
fetchDataOptions,
|
||||
NetId,
|
||||
NetIdType,
|
||||
getInstanceByAddress,
|
||||
getSubdomains,
|
||||
getConfig,
|
||||
networkConfig,
|
||||
subdomains,
|
||||
Config,
|
||||
enabledChains,
|
||||
substring,
|
||||
NoteAccount,
|
||||
parseRecoveryKey,
|
||||
getSupportedInstances,
|
||||
TreeCache,
|
||||
} from './services';
|
||||
|
||||
const DEFAULT_GAS_LIMIT = Number(process.env.DEFAULT_GAS_LIMIT) || 600_000;
|
||||
|
||||
const RELAYER_NETWORK = Number(process.env.RELAYER_NETWORK) || NetId.MAINNET;
|
||||
const DEFAULT_GAS_LIMIT = 600_000;
|
||||
const RELAYER_NETWORK = 1;
|
||||
const TOKEN_PRICE_ORACLE = '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8';
|
||||
|
||||
// Where cached events, trees, circuits, and key is saved
|
||||
const STATIC_DIR = process.env.CACHE_DIR || path.join(__dirname, '../static');
|
||||
const EVENTS_DIR = path.join(STATIC_DIR, './events');
|
||||
const TREES_DIR = path.join(STATIC_DIR, './trees');
|
||||
const MERKLE_WORKER_PATH =
|
||||
process.env.DISABLE_MERKLE_WORKER === 'true' ? undefined : path.join(STATIC_DIR, './merkleTreeWorker.js');
|
||||
|
||||
// Where we should backup notes and save events
|
||||
const USER_DIR = process.env.USER_DIR || '.';
|
||||
const SAVED_DIR = path.join(USER_DIR, './events');
|
||||
const SAVED_TREE_DIR = path.join(USER_DIR, './trees');
|
||||
|
||||
const CIRCUIT_PATH = path.join(__dirname, '../static/tornado.json');
|
||||
const KEY_PATH = path.join(__dirname, '../static/tornadoProvingKey.bin');
|
||||
@ -116,7 +107,6 @@ export type commonProgramOptions = {
|
||||
graph?: string;
|
||||
ethGraph?: string;
|
||||
disableGraph?: boolean;
|
||||
accountKey?: string;
|
||||
relayer?: string;
|
||||
walletWithdrawal?: boolean;
|
||||
torPort?: number;
|
||||
@ -171,7 +161,6 @@ export async function getProgramOptions(options: commonProgramOptions): Promise<
|
||||
graph: options.graph || (process.env.GRAPH_URL ? parseUrl(process.env.GRAPH_URL) : undefined),
|
||||
ethGraph: options.ethGraph || (process.env.ETHGRAPH_URL ? parseUrl(process.env.ETHGRAPH_URL) : undefined),
|
||||
disableGraph: Boolean(options.disableGraph) || (process.env.DISABLE_GRAPH === 'true' ? true : undefined),
|
||||
accountKey: options.accountKey || (process.env.ACCOUNT_KEY ? parseRecoveryKey(process.env.ACCOUNT_KEY) : undefined),
|
||||
relayer: options.relayer || (process.env.RELAYER ? parseRelayer(process.env.RELAYER) : undefined),
|
||||
walletWithdrawal:
|
||||
Boolean(options.walletWithdrawal) || (process.env.WALLET_WITHDRAWAL === 'true' ? true : undefined),
|
||||
@ -232,7 +221,7 @@ export function getProgramGraphAPI(options: commonProgramOptions, config: Config
|
||||
}
|
||||
|
||||
export function getProgramProvider(
|
||||
netId: NetIdType,
|
||||
netId: BigNumberish,
|
||||
rpcUrl: string = '',
|
||||
config: Config,
|
||||
providerOptions?: getProviderOptions,
|
||||
@ -271,7 +260,7 @@ export async function getProgramRelayer({
|
||||
}: {
|
||||
options: commonProgramOptions;
|
||||
fetchDataOptions?: fetchDataOptions;
|
||||
netId: NetIdType;
|
||||
netId: number | string;
|
||||
}): Promise<{
|
||||
validRelayers?: RelayerInfo[] | Relayer[];
|
||||
invalidRelayers?: RelayerError[];
|
||||
@ -279,11 +268,9 @@ export async function getProgramRelayer({
|
||||
}> {
|
||||
const { ethRpc, ethGraph, relayer, disableGraph } = options;
|
||||
|
||||
const netConfig = getConfig(netId);
|
||||
const netConfig = networkConfig[`netId${netId}`];
|
||||
|
||||
const ethConfig = getConfig(RELAYER_NETWORK);
|
||||
|
||||
const subdomains = getSubdomains();
|
||||
const ethConfig = networkConfig[`netId${RELAYER_NETWORK}`];
|
||||
|
||||
const {
|
||||
aggregatorContract,
|
||||
@ -292,7 +279,7 @@ export async function getProgramRelayer({
|
||||
constants: { REGISTRY_BLOCK },
|
||||
} = ethConfig;
|
||||
|
||||
const provider = getProgramProvider(RELAYER_NETWORK, ethRpc, ethConfig, {
|
||||
const provider = getProgramProvider(1, ethRpc, ethConfig, {
|
||||
...fetchDataOptions,
|
||||
});
|
||||
|
||||
@ -333,11 +320,7 @@ export async function getProgramRelayer({
|
||||
relayerClient.selectedRelayer = {
|
||||
netId: relayerStatus.netId,
|
||||
url: relayerStatus.url,
|
||||
hostname: new URL(relayerStatus.url).hostname,
|
||||
rewardAccount: getAddress(relayerStatus.rewardAccount),
|
||||
instances: getSupportedInstances(relayerStatus.instances),
|
||||
gasPrice: relayerStatus.gasPrices?.fast,
|
||||
ethPrices: relayerStatus.ethPrices,
|
||||
rewardAccount: relayerStatus.rewardAccount,
|
||||
currentQueue: relayerStatus.currentQueue,
|
||||
tornadoServiceFee: relayerStatus.tornadoServiceFee,
|
||||
};
|
||||
@ -353,7 +336,13 @@ export async function getProgramRelayer({
|
||||
const relayerStatus = validRelayers[0];
|
||||
|
||||
if (relayerStatus) {
|
||||
relayerClient.selectedRelayer = relayerStatus;
|
||||
relayerClient.selectedRelayer = {
|
||||
netId: relayerStatus.netId,
|
||||
url: relayerStatus.url,
|
||||
rewardAccount: relayerStatus.rewardAccount,
|
||||
currentQueue: relayerStatus.currentQueue,
|
||||
tornadoServiceFee: relayerStatus.tornadoServiceFee,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
@ -374,7 +363,13 @@ export async function getProgramRelayer({
|
||||
const relayerStatus = relayerClient.pickWeightedRandomRelayer(validRelayers);
|
||||
|
||||
if (relayerStatus) {
|
||||
relayerClient.selectedRelayer = relayerStatus;
|
||||
relayerClient.selectedRelayer = {
|
||||
netId: relayerStatus.netId,
|
||||
url: relayerStatus.url,
|
||||
rewardAccount: relayerStatus.rewardAccount,
|
||||
currentQueue: relayerStatus.currentQueue,
|
||||
tornadoServiceFee: relayerStatus.tornadoServiceFee,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
@ -459,10 +454,10 @@ export function tornadoProgram() {
|
||||
.argument('<netId>', 'Network Chain ID to connect with (see https://chainlist.org for examples)', parseNumber)
|
||||
.argument('<currency>', 'Currency to deposit on Tornado Cash')
|
||||
.argument('<amount>', 'Amount to deposit on Tornado Cash')
|
||||
.action(async (netId: NetIdType, currency: string, amount: string) => {
|
||||
.action(async (netId: string | number, currency: string, amount: string) => {
|
||||
currency = currency.toLowerCase();
|
||||
|
||||
const config = getConfig(netId);
|
||||
const config = networkConfig[`netId${netId}`];
|
||||
|
||||
const {
|
||||
routerContract,
|
||||
@ -519,17 +514,16 @@ export function tornadoProgram() {
|
||||
.argument('<netId>', 'Network Chain ID to connect with (see https://chainlist.org for examples)', parseNumber)
|
||||
.argument('<currency>', 'Currency to deposit on Tornado Cash')
|
||||
.argument('<amount>', 'Amount to deposit on Tornado Cash')
|
||||
.action(async (netId: NetIdType, currency: string, amount: string, cmdOptions: commonProgramOptions) => {
|
||||
.action(async (netId: string | number, currency: string, amount: string, cmdOptions: commonProgramOptions) => {
|
||||
const { options, fetchDataOptions } = await getProgramOptions(cmdOptions);
|
||||
currency = currency.toLowerCase();
|
||||
const { rpc, accountKey } = options;
|
||||
const { rpc } = options;
|
||||
|
||||
const config = getConfig(netId);
|
||||
const config = networkConfig[`netId${netId}`];
|
||||
|
||||
const {
|
||||
multicallContract,
|
||||
multicall: multicallAddress,
|
||||
routerContract,
|
||||
echoContract,
|
||||
nativeCurrency,
|
||||
tokens: { [currency]: currencyConfig },
|
||||
} = config;
|
||||
@ -552,14 +546,6 @@ export function tornadoProgram() {
|
||||
provider,
|
||||
});
|
||||
|
||||
const noteAccount = accountKey
|
||||
? new NoteAccount({
|
||||
netId,
|
||||
recoveryKey: accountKey,
|
||||
Echoer: Echoer__factory.connect(echoContract, provider),
|
||||
})
|
||||
: undefined;
|
||||
|
||||
if (!signer) {
|
||||
throw new Error(
|
||||
'Signer not defined, make sure you have either viewOnly address, mnemonic, or private key configured',
|
||||
@ -567,7 +553,7 @@ export function tornadoProgram() {
|
||||
}
|
||||
|
||||
const TornadoProxy = TornadoRouter__factory.connect(routerContract, signer);
|
||||
const Multicall = Multicall__factory.connect(multicallContract, provider);
|
||||
const Multicall = Multicall__factory.connect(multicallAddress, provider);
|
||||
const Token = tokenAddress ? ERC20__factory.connect(tokenAddress, signer) : undefined;
|
||||
|
||||
const [ethBalance, tokenBalance, tokenApprovals] = await multicall(Multicall, [
|
||||
@ -576,6 +562,7 @@ export function tornadoProgram() {
|
||||
name: 'getEthBalance',
|
||||
params: [signer.address],
|
||||
},
|
||||
/* eslint-disable prettier/prettier */
|
||||
...(!isEth
|
||||
? [
|
||||
{
|
||||
@ -590,6 +577,7 @@ export function tornadoProgram() {
|
||||
},
|
||||
]
|
||||
: []),
|
||||
/* eslint-enable prettier/prettier */
|
||||
]);
|
||||
|
||||
if (isEth && denomination > ethBalance) {
|
||||
@ -621,36 +609,18 @@ export function tornadoProgram() {
|
||||
|
||||
const { note, noteHex, commitmentHex } = deposit;
|
||||
|
||||
const encryptedNote = noteAccount
|
||||
? noteAccount.encryptNote({
|
||||
address: instanceAddress,
|
||||
noteHex,
|
||||
})
|
||||
: '0x';
|
||||
|
||||
const backupFile = `./backup-tornado-${currency}-${amount}-${netId}-${noteHex.slice(0, 10)}.txt`;
|
||||
|
||||
console.log(`New deposit: ${deposit.toString()}\n`);
|
||||
|
||||
console.log(`Writing note backup at ${backupFile}\n`);
|
||||
|
||||
await writeFile(backupFile, note, { encoding: 'utf8' });
|
||||
|
||||
if (encryptedNote !== '0x') {
|
||||
console.log(`Storing encrypted note on-chain for backup (Account key: ${accountKey})\n`);
|
||||
}
|
||||
await writeFile(`./backup-tornado-${currency}-${amount}-${netId}-${noteHex.slice(0, 10)}.txt`, note, {
|
||||
encoding: 'utf8',
|
||||
});
|
||||
|
||||
await programSendTransaction({
|
||||
signer,
|
||||
options,
|
||||
populatedTransaction: await TornadoProxy.deposit.populateTransaction(
|
||||
instanceAddress,
|
||||
commitmentHex,
|
||||
encryptedNote,
|
||||
{
|
||||
populatedTransaction: await TornadoProxy.deposit.populateTransaction(instanceAddress, commitmentHex, '0x', {
|
||||
value: isEth ? denomination : BigInt(0),
|
||||
},
|
||||
),
|
||||
}),
|
||||
});
|
||||
|
||||
process.exit(0);
|
||||
@ -669,10 +639,10 @@ export function tornadoProgram() {
|
||||
|
||||
const { currency, amount, netId, commitment } = new Invoice(invoiceString);
|
||||
|
||||
const config = getConfig(netId);
|
||||
const config = networkConfig[`netId${netId}`];
|
||||
|
||||
const {
|
||||
multicallContract,
|
||||
multicall: multicallAddress,
|
||||
routerContract,
|
||||
nativeCurrency,
|
||||
tokens: { [currency]: currencyConfig },
|
||||
@ -703,7 +673,7 @@ export function tornadoProgram() {
|
||||
}
|
||||
|
||||
const TornadoProxy = TornadoRouter__factory.connect(routerContract, signer);
|
||||
const Multicall = Multicall__factory.connect(multicallContract, provider);
|
||||
const Multicall = Multicall__factory.connect(multicallAddress, provider);
|
||||
const Token = tokenAddress ? ERC20__factory.connect(tokenAddress, signer) : undefined;
|
||||
|
||||
const [ethBalance, tokenBalance, tokenApprovals] = await multicall(Multicall, [
|
||||
@ -712,6 +682,7 @@ export function tornadoProgram() {
|
||||
name: 'getEthBalance',
|
||||
params: [signer.address],
|
||||
},
|
||||
/* eslint-disable prettier/prettier */
|
||||
...(!isEth
|
||||
? [
|
||||
{
|
||||
@ -726,6 +697,7 @@ export function tornadoProgram() {
|
||||
},
|
||||
]
|
||||
: []),
|
||||
/* eslint-enable prettier/prettier */
|
||||
]);
|
||||
|
||||
if (isEth && denomination > ethBalance) {
|
||||
@ -784,15 +756,14 @@ export function tornadoProgram() {
|
||||
|
||||
const { netId, currency, amount, commitmentHex, nullifierHex, nullifier, secret } = deposit;
|
||||
|
||||
const config = getConfig(netId);
|
||||
const config = networkConfig[`netId${netId}`];
|
||||
|
||||
const {
|
||||
tornadoSubgraph,
|
||||
deployedBlock,
|
||||
nativeCurrency,
|
||||
multicallContract,
|
||||
routerContract,
|
||||
offchainOracleContract,
|
||||
multicall: multicallAddress,
|
||||
ovmGasPriceOracleContract,
|
||||
tokens: { [currency]: currencyConfig },
|
||||
} = config;
|
||||
@ -828,18 +799,17 @@ export function tornadoProgram() {
|
||||
|
||||
const Tornado = Tornado__factory.connect(instanceAddress, provider);
|
||||
const TornadoProxy = TornadoRouter__factory.connect(routerContract, !walletWithdrawal ? provider : signer);
|
||||
const Multicall = Multicall__factory.connect(multicallContract, provider);
|
||||
const Multicall = Multicall__factory.connect(multicallAddress, provider);
|
||||
|
||||
const tornadoFeeOracle = new TornadoFeeOracle(
|
||||
ovmGasPriceOracleContract
|
||||
? OvmGasPriceOracle__factory.connect(ovmGasPriceOracleContract, provider)
|
||||
: undefined,
|
||||
);
|
||||
|
||||
const tokenPriceOracle = new TokenPriceOracle(
|
||||
provider,
|
||||
Multicall,
|
||||
offchainOracleContract ? OffchainOracle__factory.connect(offchainOracleContract, provider) : undefined,
|
||||
OffchainOracle__factory.connect(TOKEN_PRICE_ORACLE, provider),
|
||||
);
|
||||
|
||||
const depositsServiceConstructor = {
|
||||
@ -879,9 +849,9 @@ export function tornadoProgram() {
|
||||
// If we have MERKLE_WORKER_PATH run worker at background otherwise resolve it here
|
||||
const depositTreeInitiator = await (async () => {
|
||||
if (MERKLE_WORKER_PATH) {
|
||||
return () => merkleTreeService.verifyTree(depositEvents) as Promise<MerkleTree>;
|
||||
return () => merkleTreeService.verifyTree({ events: depositEvents }) as Promise<MerkleTree>;
|
||||
}
|
||||
return (await merkleTreeService.verifyTree(depositEvents)) as MerkleTree;
|
||||
return (await merkleTreeService.verifyTree({ events: depositEvents })) as MerkleTree;
|
||||
})();
|
||||
|
||||
let depositTreePromise: Promise<MerkleTree> | MerkleTree;
|
||||
@ -946,6 +916,7 @@ export function tornadoProgram() {
|
||||
readFile(CIRCUIT_PATH, { encoding: 'utf8' }).then((s) => JSON.parse(s)),
|
||||
readFile(KEY_PATH).then((b) => new Uint8Array(b).buffer),
|
||||
depositTreePromise,
|
||||
/* eslint-disable prettier/prettier */
|
||||
!walletWithdrawal
|
||||
? getProgramRelayer({
|
||||
options,
|
||||
@ -953,6 +924,7 @@ export function tornadoProgram() {
|
||||
netId,
|
||||
}).then(({ relayerClient }) => relayerClient)
|
||||
: undefined,
|
||||
/* eslint-enable prettier/prettier */
|
||||
tornadoFeeOracle.fetchL1OptimismFee(),
|
||||
!isEth ? tokenPriceOracle.fetchPrices([tokenAddress as string]).then((p) => p[0]) : BigInt(0),
|
||||
provider.getFeeData(),
|
||||
@ -1146,7 +1118,7 @@ export function tornadoProgram() {
|
||||
const deposit = await Deposit.parseNote(note);
|
||||
const { netId, currency, amount, commitmentHex, nullifierHex } = deposit;
|
||||
|
||||
const config = getConfig(netId);
|
||||
const config = networkConfig[`netId${netId}`];
|
||||
|
||||
const {
|
||||
tornadoSubgraph,
|
||||
@ -1204,9 +1176,9 @@ export function tornadoProgram() {
|
||||
// If we have MERKLE_WORKER_PATH run worker at background otherwise resolve it here
|
||||
const depositTreePromise = await (async () => {
|
||||
if (MERKLE_WORKER_PATH) {
|
||||
return () => merkleTreeService.verifyTree(depositEvents) as Promise<MerkleTree>;
|
||||
return () => merkleTreeService.verifyTree({ events: depositEvents }) as Promise<MerkleTree>;
|
||||
}
|
||||
return (await merkleTreeService.verifyTree(depositEvents)) as MerkleTree;
|
||||
return (await merkleTreeService.verifyTree({ events: depositEvents })) as MerkleTree;
|
||||
})();
|
||||
|
||||
const [withdrawalEvents] = await Promise.all([
|
||||
@ -1263,31 +1235,32 @@ export function tornadoProgram() {
|
||||
});
|
||||
|
||||
program
|
||||
.command('updateEvents')
|
||||
.command('syncEvents')
|
||||
.description('Sync the local cache file of tornado cash events.\n\n')
|
||||
.argument('[netId]', 'Network Chain ID to connect with (see https://chainlist.org for examples)', parseNumber)
|
||||
.argument('[currency]', 'Currency to sync events')
|
||||
.action(
|
||||
async (netIdOpts: NetIdType | undefined, currencyOpts: string | undefined, cmdOptions: commonProgramOptions) => {
|
||||
async (
|
||||
netIdOpts: number | string | undefined,
|
||||
currencyOpts: string | undefined,
|
||||
cmdOptions: commonProgramOptions,
|
||||
) => {
|
||||
const { options, fetchDataOptions } = await getProgramOptions(cmdOptions);
|
||||
const { rpc } = options;
|
||||
|
||||
const networks = netIdOpts ? [netIdOpts] : enabledChains;
|
||||
|
||||
for (const netId of networks) {
|
||||
const config = getConfig(netId);
|
||||
const config = networkConfig[`netId${netId}`];
|
||||
const {
|
||||
tornadoSubgraph,
|
||||
registrySubgraph,
|
||||
governanceSubgraph,
|
||||
tokens,
|
||||
nativeCurrency,
|
||||
routerContract,
|
||||
echoContract,
|
||||
registryContract,
|
||||
governanceContract,
|
||||
['governance.contract.tornadocash.eth']: governanceContract,
|
||||
deployedBlock,
|
||||
constants: { GOVERNANCE_BLOCK, REGISTRY_BLOCK, NOTE_ACCOUNT_BLOCK, ENCRYPTED_NOTES_BLOCK },
|
||||
constants: { GOVERNANCE_BLOCK, REGISTRY_BLOCK, ENCRYPTED_NOTES_BLOCK },
|
||||
} = config;
|
||||
|
||||
const provider = getProgramProvider(netId, rpc, config, {
|
||||
@ -1299,8 +1272,9 @@ export function tornadoProgram() {
|
||||
const governanceService = new NodeGovernanceService({
|
||||
netId,
|
||||
provider,
|
||||
graphApi,
|
||||
subgraphName: governanceSubgraph,
|
||||
// to-do connect governance with subgraph
|
||||
graphApi: '',
|
||||
subgraphName: '',
|
||||
Governance: Governance__factory.connect(governanceContract, provider),
|
||||
deployedBlock: GOVERNANCE_BLOCK,
|
||||
fetchDataOptions,
|
||||
@ -1327,20 +1301,6 @@ export function tornadoProgram() {
|
||||
await registryService.updateEvents();
|
||||
}
|
||||
|
||||
const echoService = new NodeEchoService({
|
||||
netId,
|
||||
provider,
|
||||
graphApi,
|
||||
subgraphName: tornadoSubgraph,
|
||||
Echoer: Echoer__factory.connect(echoContract, provider),
|
||||
deployedBlock: NOTE_ACCOUNT_BLOCK,
|
||||
fetchDataOptions,
|
||||
cacheDirectory: EVENTS_DIR,
|
||||
userDirectory: SAVED_DIR,
|
||||
});
|
||||
|
||||
await echoService.updateEvents();
|
||||
|
||||
const encryptedNotesService = new NodeEncryptedNotesService({
|
||||
netId,
|
||||
provider,
|
||||
@ -1399,31 +1359,23 @@ export function tornadoProgram() {
|
||||
merkleWorkerPath: MERKLE_WORKER_PATH,
|
||||
});
|
||||
|
||||
const treeCache = new TreeCache({
|
||||
netId,
|
||||
amount,
|
||||
currency,
|
||||
userDirectory: SAVED_TREE_DIR,
|
||||
});
|
||||
|
||||
const depositEvents = (await depositsService.updateEvents()).events as DepositsEvents[];
|
||||
const depositEvents = (await depositsService.updateEvents()).events;
|
||||
|
||||
// If we have MERKLE_WORKER_PATH run worker at background otherwise resolve it here
|
||||
const depositTreePromise = await (async () => {
|
||||
if (MERKLE_WORKER_PATH) {
|
||||
return () => merkleTreeService.verifyTree(depositEvents) as Promise<MerkleTree>;
|
||||
return () =>
|
||||
merkleTreeService.verifyTree({ events: depositEvents as DepositsEvents[] }) as Promise<MerkleTree>;
|
||||
}
|
||||
return (await merkleTreeService.verifyTree(depositEvents)) as MerkleTree;
|
||||
return (await merkleTreeService.verifyTree({
|
||||
events: depositEvents as DepositsEvents[],
|
||||
})) as MerkleTree;
|
||||
})();
|
||||
|
||||
const [tree] = await Promise.all([
|
||||
typeof depositTreePromise === 'function' ? depositTreePromise() : depositTreePromise,
|
||||
await Promise.all([
|
||||
withdrawalsService.updateEvents(),
|
||||
typeof depositTreePromise === 'function' ? depositTreePromise() : depositTreePromise,
|
||||
]);
|
||||
|
||||
if (nativeCurrency === currency) {
|
||||
await treeCache.createTree(depositEvents, tree);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1436,7 +1388,7 @@ export function tornadoProgram() {
|
||||
.command('relayers')
|
||||
.description('List all registered relayers from the tornado cash registry.\n\n')
|
||||
.argument('<netId>', 'Network Chain ID to connect with (see https://chainlist.org for examples)', parseNumber)
|
||||
.action(async (netIdOpts: NetIdType, cmdOptions: commonProgramOptions) => {
|
||||
.action(async (netIdOpts: number | string, cmdOptions: commonProgramOptions) => {
|
||||
const { options, fetchDataOptions } = await getProgramOptions(cmdOptions);
|
||||
|
||||
const allRelayers = await getProgramRelayer({
|
||||
@ -1494,199 +1446,6 @@ export function tornadoProgram() {
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
program
|
||||
.command('createAccount')
|
||||
.description(
|
||||
'Creates and save on-chain account that would store encrypted notes. \n\n' +
|
||||
'Would first lookup on on-chain records to see if the notes are stored. \n\n' +
|
||||
'Requires a valid signable wallet (mnemonic or a private key) to work (Since they would encrypt or encrypted)',
|
||||
)
|
||||
.argument('<netId>', 'Network Chain ID to connect with (see https://chainlist.org for examples)', parseNumber)
|
||||
.action(async (netId: NetIdType, cmdOptions: commonProgramOptions) => {
|
||||
const { options, fetchDataOptions } = await getProgramOptions(cmdOptions);
|
||||
const { rpc } = options;
|
||||
|
||||
const config = getConfig(netId);
|
||||
|
||||
const {
|
||||
echoContract,
|
||||
tornadoSubgraph,
|
||||
constants: { ['NOTE_ACCOUNT_BLOCK']: deployedBlock },
|
||||
} = config;
|
||||
|
||||
const provider = getProgramProvider(netId, rpc, config, {
|
||||
...fetchDataOptions,
|
||||
});
|
||||
|
||||
const signer = getProgramSigner({
|
||||
options,
|
||||
provider,
|
||||
});
|
||||
|
||||
const graphApi = getProgramGraphAPI(options, config);
|
||||
|
||||
if (!signer || signer instanceof VoidSigner) {
|
||||
throw new Error(
|
||||
'No wallet found, make your you have supplied a valid mnemonic or private key before using this command',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find for any existing note accounts
|
||||
*/
|
||||
const walletPublicKey = NoteAccount.getWalletPublicKey(signer);
|
||||
|
||||
const Echoer = Echoer__factory.connect(echoContract, provider);
|
||||
|
||||
const newAccount = new NoteAccount({
|
||||
netId,
|
||||
Echoer,
|
||||
});
|
||||
|
||||
const echoService = new NodeEchoService({
|
||||
netId,
|
||||
provider,
|
||||
graphApi,
|
||||
subgraphName: tornadoSubgraph,
|
||||
Echoer,
|
||||
deployedBlock,
|
||||
fetchDataOptions,
|
||||
cacheDirectory: EVENTS_DIR,
|
||||
userDirectory: SAVED_DIR,
|
||||
});
|
||||
|
||||
console.log('Getting historic note accounts would take a while\n');
|
||||
|
||||
const echoEvents = (await echoService.updateEvents()).events;
|
||||
|
||||
const userEvents = echoEvents.filter(({ address }) => address === signer.address);
|
||||
|
||||
const existingAccounts = newAccount.decryptAccountsWithWallet(signer, userEvents);
|
||||
|
||||
const accountsTable = new Table();
|
||||
|
||||
if (existingAccounts.length) {
|
||||
accountsTable.push(
|
||||
[{ colSpan: 2, content: `Note Accounts (${netId})`, hAlign: 'center' }],
|
||||
[{ colSpan: 2, content: `Backed up by: ${signer.address}`, hAlign: 'center' }],
|
||||
['blockNumber', 'noteAccount'].map((content) => ({ content: colors.red.bold(content) })),
|
||||
...existingAccounts.map(({ blockNumber, recoveryKey }) => {
|
||||
return [blockNumber, recoveryKey];
|
||||
}),
|
||||
);
|
||||
|
||||
console.log(accountsTable.toString() + '\n');
|
||||
} else {
|
||||
accountsTable.push(
|
||||
[{ colSpan: 1, content: `New Note Account (${netId})`, hAlign: 'center' }],
|
||||
['noteAccount'].map((content) => ({ content: colors.red.bold(content) })),
|
||||
[newAccount.recoveryKey],
|
||||
[{ colSpan: 1, content: `Would be backed up by: ${signer.address}`, hAlign: 'center' }],
|
||||
);
|
||||
|
||||
const fileName = `backup-note-account-key-0x${newAccount.recoveryKey.slice(0, 8)}.txt`;
|
||||
|
||||
console.log('\n' + accountsTable.toString() + '\n');
|
||||
|
||||
console.log(`Writing backup to ${fileName}\n`);
|
||||
|
||||
await writeFile(fileName, newAccount.recoveryKey + '\n');
|
||||
|
||||
console.log('Backup encrypted account on-chain to use on UI?\n');
|
||||
|
||||
await promptConfirmation(options.nonInteractive);
|
||||
|
||||
const { data } = newAccount.getEncryptedAccount(walletPublicKey);
|
||||
|
||||
console.log('Sending encrypted note account backup transaction through wallet\n');
|
||||
|
||||
await programSendTransaction({
|
||||
signer: signer as TornadoVoidSigner | TornadoWallet,
|
||||
options,
|
||||
populatedTransaction: await Echoer.echo.populateTransaction(data),
|
||||
});
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
program
|
||||
.command('decryptNotes')
|
||||
.description('Fetch notes from deposit events and decrypt them. \n\n' + 'Requires a valid account key to work')
|
||||
.argument('<netId>', 'Network Chain ID to connect with (see https://chainlist.org for examples)', parseNumber)
|
||||
.argument(
|
||||
'[accountKey]',
|
||||
'Account key generated from UI or the createAccount to store encrypted notes on-chain',
|
||||
parseRecoveryKey,
|
||||
)
|
||||
.action(async (netId: NetIdType, accountKey: string | undefined, cmdOptions: commonProgramOptions) => {
|
||||
const { options, fetchDataOptions } = await getProgramOptions(cmdOptions);
|
||||
const { rpc } = options;
|
||||
if (!accountKey) {
|
||||
accountKey = options.accountKey;
|
||||
}
|
||||
|
||||
const config = getConfig(netId);
|
||||
|
||||
const {
|
||||
routerContract,
|
||||
echoContract,
|
||||
tornadoSubgraph,
|
||||
constants: { ENCRYPTED_NOTES_BLOCK },
|
||||
} = config;
|
||||
|
||||
const provider = getProgramProvider(netId, rpc, config, {
|
||||
...fetchDataOptions,
|
||||
});
|
||||
|
||||
const graphApi = getProgramGraphAPI(options, config);
|
||||
|
||||
if (!accountKey) {
|
||||
throw new Error(
|
||||
'No account key find! Please supply correct account key from either UI or find one with createAccount command',
|
||||
);
|
||||
}
|
||||
|
||||
const Echoer = Echoer__factory.connect(echoContract, provider);
|
||||
|
||||
const noteAccount = new NoteAccount({
|
||||
netId,
|
||||
recoveryKey: accountKey,
|
||||
Echoer,
|
||||
});
|
||||
|
||||
const encryptedNotesService = new NodeEncryptedNotesService({
|
||||
netId,
|
||||
provider,
|
||||
graphApi,
|
||||
subgraphName: tornadoSubgraph,
|
||||
Router: TornadoRouter__factory.connect(routerContract, provider),
|
||||
deployedBlock: ENCRYPTED_NOTES_BLOCK,
|
||||
fetchDataOptions,
|
||||
cacheDirectory: EVENTS_DIR,
|
||||
userDirectory: SAVED_DIR,
|
||||
});
|
||||
|
||||
const encryptedNoteEvents = (await encryptedNotesService.updateEvents()).events;
|
||||
|
||||
const accountsTable = new Table();
|
||||
|
||||
accountsTable.push(
|
||||
[{ colSpan: 2, content: `Note Accounts (${netId})`, hAlign: 'center' }],
|
||||
[{ colSpan: 2, content: `Account key: ${accountKey}`, hAlign: 'center' }],
|
||||
['blockNumber', 'note'].map((content) => ({ content: colors.red.bold(content) })),
|
||||
...noteAccount.decryptNotes(encryptedNoteEvents).map(({ blockNumber, address, noteHex }) => {
|
||||
const { amount, currency } = getInstanceByAddress({ netId, address }) as { amount: string; currency: string };
|
||||
|
||||
return [blockNumber, `tornado-${currency}-${amount}-${netId}-${noteHex}`];
|
||||
}),
|
||||
);
|
||||
|
||||
console.log('\n' + accountsTable.toString() + '\n');
|
||||
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
program
|
||||
.command('send')
|
||||
.description('Send ETH or ERC20 token to address.\n\n')
|
||||
@ -1696,7 +1455,7 @@ export function tornadoProgram() {
|
||||
.argument('[token]', 'ERC20 Token Contract to check Token Balance', parseAddress)
|
||||
.action(
|
||||
async (
|
||||
netId: NetIdType,
|
||||
netId: string | number,
|
||||
to: string,
|
||||
amountArgs: number | undefined,
|
||||
tokenArgs: string | undefined,
|
||||
@ -1705,9 +1464,9 @@ export function tornadoProgram() {
|
||||
const { options, fetchDataOptions } = await getProgramOptions(cmdOptions);
|
||||
const { rpc, token: tokenOpts } = options;
|
||||
|
||||
const config = getConfig(netId);
|
||||
const config = networkConfig[`netId${netId}`];
|
||||
|
||||
const { currencyName, multicallContract } = config;
|
||||
const { currencyName, multicall: multicallAddress } = config;
|
||||
|
||||
const provider = getProgramProvider(netId, rpc, config, {
|
||||
...fetchDataOptions,
|
||||
@ -1723,7 +1482,7 @@ export function tornadoProgram() {
|
||||
|
||||
const tokenAddress = tokenArgs ? parseAddress(tokenArgs) : tokenOpts;
|
||||
|
||||
const Multicall = Multicall__factory.connect(multicallContract, provider);
|
||||
const Multicall = Multicall__factory.connect(multicallAddress, provider);
|
||||
const Token = (tokenAddress ? ERC20__factory.connect(tokenAddress, signer) : undefined) as ERC20;
|
||||
|
||||
// Fetching feeData or nonce is unnecessary however we do this to estimate transfer amounts
|
||||
@ -1749,6 +1508,7 @@ export function tornadoProgram() {
|
||||
const txGasPrice = feeData.maxFeePerGas
|
||||
? feeData.maxFeePerGas + (feeData.maxPriorityFeePerGas || BigInt(0))
|
||||
: feeData.gasPrice || BigInt(0);
|
||||
/* eslint-disable prettier/prettier */
|
||||
const txFees = feeData.maxFeePerGas
|
||||
? {
|
||||
maxFeePerGas: feeData.maxFeePerGas,
|
||||
@ -1783,11 +1543,6 @@ export function tornadoProgram() {
|
||||
const initCost = txGasPrice * BigInt('400000');
|
||||
toSend = ethBalance - initCost;
|
||||
|
||||
if (ethBalance === BigInt(0) || ethBalance < initCost) {
|
||||
const errMsg = `Invalid ${currencyName} balance, wants ${formatEther(initCost)} have ${formatEther(ethBalance)}`;
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
|
||||
const estimatedGas = await provider.estimateGas({
|
||||
type: txType,
|
||||
from: signer.address,
|
||||
@ -1797,10 +1552,10 @@ export function tornadoProgram() {
|
||||
...txFees,
|
||||
});
|
||||
|
||||
const bumpedGas =
|
||||
estimatedGas !== BigInt(21000) && signer.gasLimitBump
|
||||
const bumpedGas = (estimatedGas !== BigInt(21000) && signer.gasLimitBump
|
||||
? (estimatedGas * (BigInt(10000) + BigInt(signer.gasLimitBump))) / BigInt(10000)
|
||||
: estimatedGas;
|
||||
: estimatedGas
|
||||
);
|
||||
|
||||
toSend = ethBalance - txGasPrice * bumpedGas;
|
||||
}
|
||||
@ -1820,6 +1575,7 @@ export function tornadoProgram() {
|
||||
...txFees,
|
||||
}),
|
||||
});
|
||||
/* eslint-enable prettier/prettier */
|
||||
|
||||
process.exit(0);
|
||||
},
|
||||
@ -1833,7 +1589,7 @@ export function tornadoProgram() {
|
||||
.argument('[token]', 'ERC20 Token Contract to check Token Balance', parseAddress)
|
||||
.action(
|
||||
async (
|
||||
netId: NetIdType,
|
||||
netId: string | number,
|
||||
addressArgs: string | undefined,
|
||||
tokenArgs: string | undefined,
|
||||
cmdOptions: commonProgramOptions,
|
||||
@ -1841,9 +1597,14 @@ export function tornadoProgram() {
|
||||
const { options, fetchDataOptions } = await getProgramOptions(cmdOptions);
|
||||
const { rpc, token: tokenOpts } = options;
|
||||
|
||||
const config = getConfig(netId);
|
||||
const config = networkConfig[`netId${netId}`];
|
||||
|
||||
const { currencyName, multicallContract, tornContract, tokens } = config;
|
||||
const {
|
||||
currencyName,
|
||||
multicall: multicallAddress,
|
||||
['torn.contract.tornadocash.eth']: tornTokenAddress,
|
||||
tokens,
|
||||
} = config;
|
||||
|
||||
const provider = getProgramProvider(netId, rpc, config, {
|
||||
...fetchDataOptions,
|
||||
@ -1856,14 +1617,14 @@ export function tornadoProgram() {
|
||||
throw new Error('Address is required however no user address is supplied');
|
||||
}
|
||||
|
||||
const Multicall = Multicall__factory.connect(multicallContract, provider);
|
||||
const Multicall = Multicall__factory.connect(multicallAddress, provider);
|
||||
|
||||
const tokenAddresses = Object.values(tokens)
|
||||
.map(({ tokenAddress }) => tokenAddress)
|
||||
.filter((t) => t) as string[];
|
||||
|
||||
if (tornContract) {
|
||||
tokenAddresses.push(tornContract);
|
||||
if (tornTokenAddress) {
|
||||
tokenAddresses.push(tornTokenAddress);
|
||||
}
|
||||
|
||||
const tokenBalances = await getTokenBalances({
|
||||
@ -1901,7 +1662,7 @@ export function tornadoProgram() {
|
||||
|
||||
const netId = Number(deserializedTx.chainId);
|
||||
|
||||
const config = getConfig(netId);
|
||||
const config = networkConfig[`netId${netId}`];
|
||||
|
||||
const provider = getProgramProvider(netId, rpc, config, {
|
||||
...fetchDataOptions,
|
||||
@ -1918,6 +1679,7 @@ export function tornadoProgram() {
|
||||
options,
|
||||
populatedTransaction: deserializedTx,
|
||||
});
|
||||
/* eslint-enable prettier/prettier */
|
||||
|
||||
process.exit(0);
|
||||
});
|
||||
@ -1936,7 +1698,7 @@ export function tornadoProgram() {
|
||||
throw new Error('NetId for the transaction is invalid, this command only supports EIP-155 transactions');
|
||||
}
|
||||
|
||||
const config = getConfig(netId);
|
||||
const config = networkConfig[`netId${netId}`];
|
||||
|
||||
const provider = getProgramProvider(netId, rpc, config, {
|
||||
...fetchDataOptions,
|
||||
@ -1950,24 +1712,13 @@ export function tornadoProgram() {
|
||||
});
|
||||
|
||||
// common options
|
||||
/* eslint-disable prettier/prettier */
|
||||
program.commands.forEach((cmd) => {
|
||||
cmd.option('-r, --rpc <RPC_URL>', 'The RPC that CLI should interact with', parseUrl);
|
||||
cmd.option('-e, --eth-rpc <ETHRPC_URL>', 'The Ethereum Mainnet RPC that CLI should interact with', parseUrl);
|
||||
cmd.option('-g, --graph <GRAPH_URL>', 'The Subgraph API that CLI should interact with', parseUrl);
|
||||
cmd.option(
|
||||
'-G, --eth-graph <ETHGRAPH_URL>',
|
||||
'The Ethereum Mainnet Subgraph API that CLI should interact with',
|
||||
parseUrl,
|
||||
);
|
||||
cmd.option(
|
||||
'-d, --disable-graph',
|
||||
'Disable Graph API - Does not enable Subgraph API and use only local RPC as an event source',
|
||||
);
|
||||
cmd.option(
|
||||
'-a, --account-key <ACCOUNT_KEY>',
|
||||
'Account key generated from UI or the createAccount to store encrypted notes on-chain',
|
||||
parseRecoveryKey,
|
||||
);
|
||||
cmd.option('-G, --eth-graph <ETHGRAPH_URL>', 'The Ethereum Mainnet Subgraph API that CLI should interact with', parseUrl);
|
||||
cmd.option('-d, --disable-graph', 'Disable Graph API - Does not enable Subgraph API and use only local RPC as an event source');
|
||||
cmd.option('-R, --relayer <RELAYER>', 'Withdraw via relayer (Should be either .eth name or URL)', parseRelayer);
|
||||
cmd.option('-w, --wallet-withdrawal', 'Withdrawal via wallet (Should not be linked with deposits)');
|
||||
cmd.option('-T, --tor-port <TOR_PORT>', 'Optional tor port', parseNumber);
|
||||
@ -1979,13 +1730,13 @@ export function tornadoProgram() {
|
||||
);
|
||||
cmd.option(
|
||||
'-m, --mnemonic <MNEMONIC>',
|
||||
'Wallet BIP39 Mnemonic Phrase - If you did not add it to .env file and it is needed for operation',
|
||||
'Wallet BIP39 Mnemonic Phrase - If you didn\'t add it to .env file and it is needed for operation',
|
||||
parseMnemonic,
|
||||
);
|
||||
cmd.option('-i, --mnemonic-index <MNEMONIC_INDEX>', 'Optional wallet mnemonic index', parseNumber);
|
||||
cmd.option(
|
||||
'-p, --private-key <PRIVATE_KEY>',
|
||||
'Wallet private key - If you did not add it to .env file and it is needed for operation',
|
||||
'Wallet private key - If you didn\'t add it to .env file and it is needed for operation',
|
||||
parseKey,
|
||||
);
|
||||
cmd.option(
|
||||
@ -1994,6 +1745,7 @@ export function tornadoProgram() {
|
||||
);
|
||||
cmd.option('-l, --local-rpc', 'Local node mode - Does not submit signed transaction to the node');
|
||||
});
|
||||
/* eslint-enable prettier/prettier */
|
||||
|
||||
return program;
|
||||
}
|
||||
|
@ -37,21 +37,22 @@ export function unzipAsync(data: Uint8Array): Promise<Unzipped> {
|
||||
});
|
||||
}
|
||||
|
||||
export async function saveUserFile({
|
||||
fileName,
|
||||
export async function saveEvents<T extends MinimalEvents>({
|
||||
name,
|
||||
userDirectory,
|
||||
dataString,
|
||||
events,
|
||||
}: {
|
||||
fileName: string;
|
||||
name: string;
|
||||
userDirectory: string;
|
||||
dataString: string;
|
||||
events: T[];
|
||||
}) {
|
||||
fileName = fileName.toLowerCase();
|
||||
|
||||
const fileName = `${name}.json`.toLowerCase();
|
||||
const filePath = path.join(userDirectory, fileName);
|
||||
|
||||
const stringEvents = JSON.stringify(events, null, 2) + '\n';
|
||||
|
||||
const payload = await zipAsync({
|
||||
[fileName]: new TextEncoder().encode(dataString),
|
||||
[fileName]: new TextEncoder().encode(stringEvents),
|
||||
});
|
||||
|
||||
if (!(await existsAsync(userDirectory))) {
|
||||
@ -59,7 +60,7 @@ export async function saveUserFile({
|
||||
}
|
||||
|
||||
await writeFile(filePath + '.zip', payload);
|
||||
await writeFile(filePath, dataString);
|
||||
await writeFile(filePath, stringEvents);
|
||||
}
|
||||
|
||||
export async function loadSavedEvents<T extends MinimalEvents>({
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { bnToBytes, bytesToBN, leBuff2Int, leInt2Buff, rBigInt, toFixedHex } from './utils';
|
||||
import { buffPedersenHash } from './pedersen';
|
||||
import type { NetIdType } from './networkConfig';
|
||||
|
||||
export type DepositType = {
|
||||
currency: string;
|
||||
amount: string;
|
||||
netId: NetIdType;
|
||||
netId: string | number;
|
||||
};
|
||||
|
||||
export type createDepositParams = {
|
||||
@ -62,7 +61,7 @@ export async function createDeposit({ nullifier, secret }: createDepositParams):
|
||||
export interface DepositConstructor {
|
||||
currency: string;
|
||||
amount: string;
|
||||
netId: NetIdType;
|
||||
netId: number;
|
||||
nullifier: bigint;
|
||||
secret: bigint;
|
||||
note: string;
|
||||
@ -75,7 +74,7 @@ export interface DepositConstructor {
|
||||
export class Deposit {
|
||||
currency: string;
|
||||
amount: string;
|
||||
netId: NetIdType;
|
||||
netId: number;
|
||||
|
||||
nullifier: bigint;
|
||||
secret: bigint;
|
||||
@ -149,7 +148,7 @@ export class Deposit {
|
||||
const newDeposit = new Deposit({
|
||||
currency: currency.toLowerCase(),
|
||||
amount: amount,
|
||||
netId,
|
||||
netId: Number(netId),
|
||||
note: `tornado-${currency.toLowerCase()}-${amount}-${netId}-${depositObject.noteHex}`,
|
||||
noteHex: depositObject.noteHex,
|
||||
invoice: `tornadoInvoice-${currency.toLowerCase()}-${amount}-${netId}-${depositObject.commitmentHex}`,
|
||||
@ -183,14 +182,14 @@ export class Deposit {
|
||||
const invoice = `tornadoInvoice-${currency}-${amount}-${netId}-${depositObject.commitmentHex}`;
|
||||
|
||||
const newDeposit = new Deposit({
|
||||
currency,
|
||||
amount,
|
||||
netId,
|
||||
currency: currency,
|
||||
amount: amount,
|
||||
netId: netId,
|
||||
note: noteString,
|
||||
noteHex: depositObject.noteHex,
|
||||
invoice,
|
||||
nullifier,
|
||||
secret,
|
||||
invoice: invoice,
|
||||
nullifier: nullifier,
|
||||
secret: secret,
|
||||
commitmentHex: depositObject.commitmentHex,
|
||||
nullifierHex: depositObject.nullifierHex,
|
||||
});
|
||||
@ -206,7 +205,7 @@ export type parsedInvoiceExec = DepositType & {
|
||||
export class Invoice {
|
||||
currency: string;
|
||||
amount: string;
|
||||
netId: NetIdType;
|
||||
netId: number;
|
||||
commitment: string;
|
||||
invoice: string;
|
||||
|
||||
|
@ -1,189 +0,0 @@
|
||||
import { getEncryptionPublicKey, encrypt, decrypt, EthEncryptedData } from '@metamask/eth-sig-util';
|
||||
import { Echoer } from '@tornado/contracts';
|
||||
import { Wallet, computeAddress, getAddress } from 'ethers';
|
||||
import { crypto, base64ToBytes, bytesToBase64, bytesToHex, hexToBytes, toFixedHex, concatBytes } from './utils';
|
||||
import { EchoEvents, EncryptedNotesEvents } from './events';
|
||||
import type { NetIdType } from './networkConfig';
|
||||
|
||||
export interface NoteToEncrypt {
|
||||
address: string;
|
||||
noteHex: string;
|
||||
}
|
||||
|
||||
export interface DecryptedNotes {
|
||||
blockNumber: number;
|
||||
address: string;
|
||||
noteHex: string;
|
||||
}
|
||||
|
||||
export function packEncryptedMessage({ nonce, ephemPublicKey, ciphertext }: EthEncryptedData) {
|
||||
const nonceBuf = toFixedHex(bytesToHex(base64ToBytes(nonce)), 24);
|
||||
const ephemPublicKeyBuf = toFixedHex(bytesToHex(base64ToBytes(ephemPublicKey)), 32);
|
||||
const ciphertextBuf = bytesToHex(base64ToBytes(ciphertext));
|
||||
|
||||
const messageBuff = concatBytes(hexToBytes(nonceBuf), hexToBytes(ephemPublicKeyBuf), hexToBytes(ciphertextBuf));
|
||||
|
||||
return bytesToHex(messageBuff);
|
||||
}
|
||||
|
||||
export function unpackEncryptedMessage(encryptedMessage: string) {
|
||||
const messageBuff = hexToBytes(encryptedMessage);
|
||||
const nonceBuf = bytesToBase64(messageBuff.slice(0, 24));
|
||||
const ephemPublicKeyBuf = bytesToBase64(messageBuff.slice(24, 56));
|
||||
const ciphertextBuf = bytesToBase64(messageBuff.slice(56));
|
||||
|
||||
return {
|
||||
messageBuff: bytesToHex(messageBuff),
|
||||
version: 'x25519-xsalsa20-poly1305',
|
||||
nonce: nonceBuf,
|
||||
ephemPublicKey: ephemPublicKeyBuf,
|
||||
ciphertext: ciphertextBuf,
|
||||
} as EthEncryptedData & {
|
||||
messageBuff: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface NoteAccountConstructor {
|
||||
netId: NetIdType;
|
||||
blockNumber?: number;
|
||||
// hex
|
||||
recoveryKey?: string;
|
||||
Echoer: Echoer;
|
||||
}
|
||||
|
||||
export class NoteAccount {
|
||||
netId: NetIdType;
|
||||
blockNumber?: number;
|
||||
// Dedicated 32 bytes private key only used for note encryption, backed up to an Echoer and local for future derivation
|
||||
// Note that unlike the private key it shouldn't have the 0x prefix
|
||||
recoveryKey: string;
|
||||
// Address derived from recoveryKey, only used for frontend UI
|
||||
recoveryAddress: string;
|
||||
// Note encryption public key derived from recoveryKey
|
||||
recoveryPublicKey: string;
|
||||
Echoer: Echoer;
|
||||
|
||||
constructor({ netId, blockNumber, recoveryKey, Echoer }: NoteAccountConstructor) {
|
||||
if (!recoveryKey) {
|
||||
recoveryKey = bytesToHex(crypto.getRandomValues(new Uint8Array(32))).slice(2);
|
||||
}
|
||||
|
||||
this.netId = Math.floor(Number(netId));
|
||||
this.blockNumber = blockNumber;
|
||||
this.recoveryKey = recoveryKey;
|
||||
this.recoveryAddress = computeAddress('0x' + recoveryKey);
|
||||
this.recoveryPublicKey = getEncryptionPublicKey(recoveryKey);
|
||||
this.Echoer = Echoer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Intends to mock eth_getEncryptionPublicKey behavior from MetaMask
|
||||
* In order to make the recoveryKey retrival from Echoer possible from the bare private key
|
||||
*/
|
||||
static getWalletPublicKey(wallet: Wallet) {
|
||||
let { privateKey } = wallet;
|
||||
|
||||
if (privateKey.startsWith('0x')) {
|
||||
privateKey = privateKey.replace('0x', '');
|
||||
}
|
||||
|
||||
// Should return base64 encoded public key
|
||||
return getEncryptionPublicKey(privateKey);
|
||||
}
|
||||
|
||||
// This function intends to provide an encrypted value of recoveryKey for an on-chain Echoer backup purpose
|
||||
// Thus, the pubKey should be derived by a Wallet instance or from Web3 wallets
|
||||
// pubKey: base64 encoded 32 bytes key from https://docs.metamask.io/wallet/reference/eth_getencryptionpublickey/
|
||||
getEncryptedAccount(walletPublicKey: string) {
|
||||
const encryptedData = encrypt({
|
||||
publicKey: walletPublicKey,
|
||||
data: this.recoveryKey,
|
||||
version: 'x25519-xsalsa20-poly1305',
|
||||
});
|
||||
|
||||
const data = packEncryptedMessage(encryptedData);
|
||||
|
||||
return {
|
||||
// Use this later to save hexPrivateKey generated with
|
||||
// Buffer.from(JSON.stringify(encryptedData)).toString('hex')
|
||||
// As we don't use buffer with this library we should leave UI to do the rest
|
||||
encryptedData,
|
||||
// Data that could be used as an echo(data) params
|
||||
data,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt Echoer backuped note encryption account with private keys
|
||||
*/
|
||||
decryptAccountsWithWallet(wallet: Wallet, events: EchoEvents[]): NoteAccount[] {
|
||||
let { privateKey } = wallet;
|
||||
|
||||
if (privateKey.startsWith('0x')) {
|
||||
privateKey = privateKey.replace('0x', '');
|
||||
}
|
||||
|
||||
const decryptedEvents = [];
|
||||
|
||||
for (const event of events) {
|
||||
try {
|
||||
const unpackedMessage = unpackEncryptedMessage(event.encryptedAccount);
|
||||
|
||||
const recoveryKey = decrypt({
|
||||
encryptedData: unpackedMessage,
|
||||
privateKey,
|
||||
});
|
||||
|
||||
decryptedEvents.push(
|
||||
new NoteAccount({
|
||||
netId: this.netId,
|
||||
blockNumber: event.blockNumber,
|
||||
recoveryKey,
|
||||
Echoer: this.Echoer,
|
||||
}),
|
||||
);
|
||||
} catch {
|
||||
// decryption may fail for invalid accounts
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return decryptedEvents;
|
||||
}
|
||||
|
||||
decryptNotes(events: EncryptedNotesEvents[]): DecryptedNotes[] {
|
||||
const decryptedEvents = [];
|
||||
|
||||
for (const event of events) {
|
||||
try {
|
||||
const unpackedMessage = unpackEncryptedMessage(event.encryptedNote);
|
||||
|
||||
const [address, noteHex] = decrypt({
|
||||
encryptedData: unpackedMessage,
|
||||
privateKey: this.recoveryKey,
|
||||
}).split('-');
|
||||
|
||||
decryptedEvents.push({
|
||||
blockNumber: event.blockNumber,
|
||||
address: getAddress(address),
|
||||
noteHex,
|
||||
});
|
||||
} catch {
|
||||
// decryption may fail for foreign notes
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return decryptedEvents;
|
||||
}
|
||||
|
||||
encryptNote({ address, noteHex }: NoteToEncrypt) {
|
||||
const encryptedData = encrypt({
|
||||
publicKey: this.recoveryPublicKey,
|
||||
data: `${address}-${noteHex}`,
|
||||
version: 'x25519-xsalsa20-poly1305',
|
||||
});
|
||||
|
||||
return packEncryptedMessage(encryptedData);
|
||||
}
|
||||
}
|
@ -1,12 +1,5 @@
|
||||
import { BaseContract, Provider, EventLog, TransactionResponse, getAddress, Block, ContractEventName } from 'ethers';
|
||||
import type {
|
||||
Tornado,
|
||||
TornadoRouter,
|
||||
TornadoProxyLight,
|
||||
Governance,
|
||||
RelayerRegistry,
|
||||
Echoer,
|
||||
} from '@tornado/contracts';
|
||||
import type { Tornado, TornadoRouter, TornadoProxyLight, Governance, RelayerRegistry } from '@tornado/contracts';
|
||||
import * as graph from '../graphql';
|
||||
import {
|
||||
BatchEventsService,
|
||||
@ -16,28 +9,25 @@ import {
|
||||
BatchBlockOnProgress,
|
||||
} from '../batch';
|
||||
import { fetchDataOptions } from '../providers';
|
||||
import type { NetIdType } from '../networkConfig';
|
||||
import type {
|
||||
BaseEvents,
|
||||
MinimalEvents,
|
||||
DepositsEvents,
|
||||
WithdrawalsEvents,
|
||||
EncryptedNotesEvents,
|
||||
AllGovernanceEvents,
|
||||
GovernanceProposalCreatedEvents,
|
||||
GovernanceVotedEvents,
|
||||
GovernanceDelegatedEvents,
|
||||
GovernanceUndelegatedEvents,
|
||||
RegistersEvents,
|
||||
BaseGraphEvents,
|
||||
EchoEvents,
|
||||
} from './types';
|
||||
|
||||
export const DEPOSIT = 'deposit';
|
||||
export const WITHDRAWAL = 'withdrawal';
|
||||
|
||||
export type BaseEventsServiceConstructor = {
|
||||
netId: NetIdType;
|
||||
netId: number | string;
|
||||
provider: Provider;
|
||||
graphApi?: string;
|
||||
subgraphName?: string;
|
||||
@ -67,7 +57,7 @@ export type BaseGraphParams = {
|
||||
};
|
||||
|
||||
export class BaseEventsService<EventType extends MinimalEvents> {
|
||||
netId: NetIdType;
|
||||
netId: number | string;
|
||||
provider: Provider;
|
||||
graphApi?: string;
|
||||
subgraphName?: string;
|
||||
@ -325,7 +315,7 @@ export class BaseEventsService<EventType extends MinimalEvents> {
|
||||
}
|
||||
|
||||
export type BaseDepositsServiceConstructor = {
|
||||
netId: NetIdType;
|
||||
netId: number | string;
|
||||
provider: Provider;
|
||||
graphApi?: string;
|
||||
subgraphName?: string;
|
||||
@ -464,78 +454,8 @@ export class BaseDepositsService extends BaseEventsService<DepositsEvents | With
|
||||
}
|
||||
}
|
||||
|
||||
export type BaseEchoServiceConstructor = {
|
||||
netId: NetIdType;
|
||||
provider: Provider;
|
||||
graphApi?: string;
|
||||
subgraphName?: string;
|
||||
Echoer: Echoer;
|
||||
deployedBlock?: number;
|
||||
fetchDataOptions?: fetchDataOptions;
|
||||
};
|
||||
|
||||
export class BaseEchoService extends BaseEventsService<EchoEvents> {
|
||||
constructor({
|
||||
netId,
|
||||
provider,
|
||||
graphApi,
|
||||
subgraphName,
|
||||
Echoer,
|
||||
deployedBlock,
|
||||
fetchDataOptions,
|
||||
}: BaseEchoServiceConstructor) {
|
||||
super({ netId, provider, graphApi, subgraphName, contract: Echoer, deployedBlock, fetchDataOptions });
|
||||
}
|
||||
|
||||
getInstanceName(): string {
|
||||
return `echo_${this.netId}`;
|
||||
}
|
||||
|
||||
getType(): string {
|
||||
return 'Echo';
|
||||
}
|
||||
|
||||
getGraphMethod(): string {
|
||||
return 'getAllGraphEchoEvents';
|
||||
}
|
||||
|
||||
async formatEvents(events: EventLog[]) {
|
||||
return events
|
||||
.map(({ blockNumber, index: logIndex, transactionHash, args }) => {
|
||||
const { who, data } = args;
|
||||
|
||||
if (who && data) {
|
||||
const eventObjects = {
|
||||
blockNumber,
|
||||
logIndex,
|
||||
transactionHash,
|
||||
};
|
||||
|
||||
return {
|
||||
...eventObjects,
|
||||
address: who,
|
||||
encryptedAccount: data,
|
||||
};
|
||||
}
|
||||
})
|
||||
.filter((e) => e) as EchoEvents[];
|
||||
}
|
||||
|
||||
async getEventsFromGraph({ fromBlock }: { fromBlock: number }): Promise<BaseEvents<EchoEvents>> {
|
||||
// TheGraph doesn't support our batch sync due to missing blockNumber field
|
||||
if (!this.graphApi || this.graphApi.includes('api.thegraph.com')) {
|
||||
return {
|
||||
events: [],
|
||||
lastBlock: fromBlock,
|
||||
};
|
||||
}
|
||||
|
||||
return super.getEventsFromGraph({ fromBlock });
|
||||
}
|
||||
}
|
||||
|
||||
export type BaseEncryptedNotesServiceConstructor = {
|
||||
netId: NetIdType;
|
||||
netId: number | string;
|
||||
provider: Provider;
|
||||
graphApi?: string;
|
||||
subgraphName?: string;
|
||||
@ -591,8 +511,14 @@ export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesE
|
||||
}
|
||||
}
|
||||
|
||||
export type BaseGovernanceEventTypes =
|
||||
| GovernanceProposalCreatedEvents
|
||||
| GovernanceVotedEvents
|
||||
| GovernanceDelegatedEvents
|
||||
| GovernanceUndelegatedEvents;
|
||||
|
||||
export type BaseGovernanceServiceConstructor = {
|
||||
netId: NetIdType;
|
||||
netId: number | string;
|
||||
provider: Provider;
|
||||
graphApi?: string;
|
||||
subgraphName?: string;
|
||||
@ -601,7 +527,7 @@ export type BaseGovernanceServiceConstructor = {
|
||||
fetchDataOptions?: fetchDataOptions;
|
||||
};
|
||||
|
||||
export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents> {
|
||||
export class BaseGovernanceService extends BaseEventsService<BaseGovernanceEventTypes> {
|
||||
batchTransactionService: BatchTransactionService;
|
||||
|
||||
constructor({
|
||||
@ -630,16 +556,12 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
|
||||
}
|
||||
|
||||
getGraphMethod() {
|
||||
return 'getAllGovernanceEvents';
|
||||
return 'governanceEvents';
|
||||
}
|
||||
|
||||
async formatEvents(events: EventLog[]): Promise<AllGovernanceEvents[]> {
|
||||
const proposalEvents: GovernanceProposalCreatedEvents[] = [];
|
||||
const votedEvents: GovernanceVotedEvents[] = [];
|
||||
const delegatedEvents: GovernanceDelegatedEvents[] = [];
|
||||
const undelegatedEvents: GovernanceUndelegatedEvents[] = [];
|
||||
|
||||
events.forEach(({ blockNumber, index: logIndex, transactionHash, args, eventName: event }) => {
|
||||
async formatEvents(events: EventLog[]): Promise<BaseGovernanceEventTypes[]> {
|
||||
const formattedEvents = events
|
||||
.map(({ blockNumber, index: logIndex, transactionHash, args, eventName: event }) => {
|
||||
const eventObjects = {
|
||||
blockNumber,
|
||||
logIndex,
|
||||
@ -649,52 +571,55 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
|
||||
|
||||
if (event === 'ProposalCreated') {
|
||||
const { id, proposer, target, startTime, endTime, description } = args;
|
||||
|
||||
proposalEvents.push({
|
||||
return {
|
||||
...eventObjects,
|
||||
id: Number(id),
|
||||
id,
|
||||
proposer,
|
||||
target,
|
||||
startTime: Number(startTime),
|
||||
endTime: Number(endTime),
|
||||
startTime,
|
||||
endTime,
|
||||
description,
|
||||
});
|
||||
} as GovernanceProposalCreatedEvents;
|
||||
}
|
||||
|
||||
if (event === 'Voted') {
|
||||
const { proposalId, voter, support, votes } = args;
|
||||
|
||||
votedEvents.push({
|
||||
return {
|
||||
...eventObjects,
|
||||
proposalId: Number(proposalId),
|
||||
proposalId,
|
||||
voter,
|
||||
support,
|
||||
votes,
|
||||
from: '',
|
||||
input: '',
|
||||
});
|
||||
} as GovernanceVotedEvents;
|
||||
}
|
||||
|
||||
if (event === 'Delegated') {
|
||||
const { account, to: delegateTo } = args;
|
||||
|
||||
delegatedEvents.push({
|
||||
return {
|
||||
...eventObjects,
|
||||
account,
|
||||
delegateTo,
|
||||
});
|
||||
} as GovernanceDelegatedEvents;
|
||||
}
|
||||
|
||||
if (event === 'Undelegated') {
|
||||
const { account, from: delegateFrom } = args;
|
||||
|
||||
undelegatedEvents.push({
|
||||
return {
|
||||
...eventObjects,
|
||||
account,
|
||||
delegateFrom,
|
||||
});
|
||||
} as GovernanceUndelegatedEvents;
|
||||
}
|
||||
});
|
||||
})
|
||||
.filter((e) => e) as BaseGovernanceEventTypes[];
|
||||
|
||||
type GovernanceVotedEventsIndexed = GovernanceVotedEvents & {
|
||||
index: number;
|
||||
};
|
||||
|
||||
const votedEvents = formattedEvents
|
||||
.map((event, index) => ({ ...event, index }))
|
||||
.filter(({ event }) => event === 'Voted') as GovernanceVotedEventsIndexed[];
|
||||
|
||||
if (votedEvents.length) {
|
||||
this.updateTransactionProgress({ percentage: 0 });
|
||||
@ -703,7 +628,7 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
|
||||
...new Set(votedEvents.map(({ transactionHash }) => transactionHash)),
|
||||
]);
|
||||
|
||||
votedEvents.forEach((event, index) => {
|
||||
votedEvents.forEach((event) => {
|
||||
// eslint-disable-next-line prefer-const
|
||||
let { data: input, from } = txs.find((t) => t.hash === event.transactionHash) as TransactionResponse;
|
||||
|
||||
@ -712,17 +637,19 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
|
||||
input = '';
|
||||
}
|
||||
|
||||
votedEvents[index].from = from;
|
||||
votedEvents[index].input = input;
|
||||
// @ts-expect-error check formattedEvents types later
|
||||
formattedEvents[event.index].from = from;
|
||||
// @ts-expect-error check formattedEvents types later
|
||||
formattedEvents[event.index].input = input;
|
||||
});
|
||||
}
|
||||
|
||||
return [...proposalEvents, ...votedEvents, ...delegatedEvents, ...undelegatedEvents];
|
||||
return formattedEvents;
|
||||
}
|
||||
|
||||
async getEventsFromGraph({ fromBlock }: { fromBlock: number }): Promise<BaseEvents<AllGovernanceEvents>> {
|
||||
async getEventsFromGraph({ fromBlock }: { fromBlock: number }): Promise<BaseEvents<BaseGovernanceEventTypes>> {
|
||||
// TheGraph doesn't support governance subgraphs
|
||||
if (!this.graphApi || !this.subgraphName || this.graphApi.includes('api.thegraph.com')) {
|
||||
if (!this.graphApi || this.graphApi.includes('api.thegraph.com')) {
|
||||
return {
|
||||
events: [],
|
||||
lastBlock: fromBlock,
|
||||
@ -734,7 +661,7 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
|
||||
}
|
||||
|
||||
export type BaseRegistryServiceConstructor = {
|
||||
netId: NetIdType;
|
||||
netId: number | string;
|
||||
provider: Provider;
|
||||
graphApi?: string;
|
||||
subgraphName?: string;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Table from 'cli-table3';
|
||||
import moment from 'moment';
|
||||
import { BatchBlockOnProgress, BatchEventOnProgress } from '../batch';
|
||||
import { saveUserFile, loadSavedEvents, loadCachedEvents } from '../data';
|
||||
import { saveEvents, loadSavedEvents, loadCachedEvents } from '../data';
|
||||
import {
|
||||
BaseDepositsService,
|
||||
BaseEncryptedNotesService,
|
||||
@ -11,18 +11,9 @@ import {
|
||||
BaseEncryptedNotesServiceConstructor,
|
||||
BaseGovernanceServiceConstructor,
|
||||
BaseRegistryServiceConstructor,
|
||||
BaseEchoServiceConstructor,
|
||||
BaseEchoService,
|
||||
BaseGovernanceEventTypes,
|
||||
} from './base';
|
||||
import type {
|
||||
BaseEvents,
|
||||
DepositsEvents,
|
||||
WithdrawalsEvents,
|
||||
EncryptedNotesEvents,
|
||||
RegistersEvents,
|
||||
AllGovernanceEvents,
|
||||
EchoEvents,
|
||||
} from './types';
|
||||
import type { BaseEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, RegistersEvents } from './types';
|
||||
|
||||
export type NodeDepositsServiceConstructor = BaseDepositsServiceConstructor & {
|
||||
cacheDirectory?: string;
|
||||
@ -184,155 +175,10 @@ export class NodeDepositsService extends BaseDepositsService {
|
||||
console.log(eventTable.toString() + '\n');
|
||||
|
||||
if (this.userDirectory) {
|
||||
await saveUserFile({
|
||||
fileName: instanceName + '.json',
|
||||
await saveEvents<DepositsEvents | WithdrawalsEvents>({
|
||||
name: instanceName,
|
||||
userDirectory: this.userDirectory,
|
||||
dataString: JSON.stringify(events, null, 2) + '\n',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type NodeEchoServiceConstructor = BaseEchoServiceConstructor & {
|
||||
cacheDirectory?: string;
|
||||
userDirectory?: string;
|
||||
};
|
||||
|
||||
export class NodeEchoService extends BaseEchoService {
|
||||
cacheDirectory?: string;
|
||||
userDirectory?: string;
|
||||
|
||||
constructor({
|
||||
netId,
|
||||
provider,
|
||||
graphApi,
|
||||
subgraphName,
|
||||
Echoer,
|
||||
deployedBlock,
|
||||
fetchDataOptions,
|
||||
cacheDirectory,
|
||||
userDirectory,
|
||||
}: NodeEchoServiceConstructor) {
|
||||
super({
|
||||
netId,
|
||||
provider,
|
||||
graphApi,
|
||||
subgraphName,
|
||||
Echoer,
|
||||
deployedBlock,
|
||||
fetchDataOptions,
|
||||
});
|
||||
|
||||
this.cacheDirectory = cacheDirectory;
|
||||
this.userDirectory = userDirectory;
|
||||
}
|
||||
|
||||
updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]) {
|
||||
if (toBlock) {
|
||||
console.log(`fromBlock - ${fromBlock}`);
|
||||
console.log(`toBlock - ${toBlock}`);
|
||||
|
||||
if (count) {
|
||||
console.log(`downloaded ${type} events count - ${count}`);
|
||||
console.log('____________________________________________');
|
||||
console.log(`Fetched ${type} events from ${fromBlock} to ${toBlock}\n`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]) {
|
||||
if (toBlock) {
|
||||
console.log(`fromBlock - ${fromBlock}`);
|
||||
console.log(`toBlock - ${toBlock}`);
|
||||
|
||||
if (count) {
|
||||
console.log(`downloaded ${type} events from graph node count - ${count}`);
|
||||
console.log('____________________________________________');
|
||||
console.log(`Fetched ${type} events from graph node ${fromBlock} to ${toBlock}\n`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async getEventsFromDB() {
|
||||
if (!this.userDirectory) {
|
||||
console.log(`Updating events for ${this.netId} chain echo events\n`);
|
||||
console.log(`savedEvents count - ${0}`);
|
||||
console.log(`savedEvents lastBlock - ${this.deployedBlock}\n`);
|
||||
|
||||
return {
|
||||
events: [],
|
||||
lastBlock: this.deployedBlock,
|
||||
};
|
||||
}
|
||||
|
||||
const savedEvents = await loadSavedEvents<EchoEvents>({
|
||||
name: this.getInstanceName(),
|
||||
userDirectory: this.userDirectory,
|
||||
deployedBlock: this.deployedBlock,
|
||||
});
|
||||
|
||||
console.log(`Updating events for ${this.netId} chain echo events\n`);
|
||||
console.log(`savedEvents count - ${savedEvents.events.length}`);
|
||||
console.log(`savedEvents lastBlock - ${savedEvents.lastBlock}\n`);
|
||||
|
||||
return savedEvents;
|
||||
}
|
||||
|
||||
async getEventsFromCache() {
|
||||
if (!this.cacheDirectory) {
|
||||
console.log(`cachedEvents count - ${0}`);
|
||||
console.log(`cachedEvents lastBlock - ${this.deployedBlock}\n`);
|
||||
|
||||
return {
|
||||
events: [],
|
||||
lastBlock: this.deployedBlock,
|
||||
};
|
||||
}
|
||||
|
||||
const cachedEvents = await loadCachedEvents<EchoEvents>({
|
||||
name: this.getInstanceName(),
|
||||
cacheDirectory: this.cacheDirectory,
|
||||
deployedBlock: this.deployedBlock,
|
||||
});
|
||||
|
||||
console.log(`cachedEvents count - ${cachedEvents.events.length}`);
|
||||
console.log(`cachedEvents lastBlock - ${cachedEvents.lastBlock}\n`);
|
||||
|
||||
return cachedEvents;
|
||||
}
|
||||
|
||||
async saveEvents({ events, lastBlock }: BaseEvents<EchoEvents>) {
|
||||
const instanceName = this.getInstanceName();
|
||||
|
||||
console.log('\ntotalEvents count - ', events.length);
|
||||
console.log(
|
||||
`totalEvents lastBlock - ${events[events.length - 1] ? events[events.length - 1].blockNumber : lastBlock}\n`,
|
||||
);
|
||||
|
||||
const eventTable = new Table();
|
||||
|
||||
eventTable.push(
|
||||
[{ colSpan: 2, content: 'Echo Accounts', hAlign: 'center' }],
|
||||
['Network', `${this.netId} chain`],
|
||||
['Events', `${events.length} events`],
|
||||
[{ colSpan: 2, content: 'Latest events' }],
|
||||
...events
|
||||
.slice(events.length - 10)
|
||||
.reverse()
|
||||
.map(({ blockNumber }, index) => {
|
||||
const eventIndex = events.length - index;
|
||||
|
||||
return [eventIndex, blockNumber];
|
||||
}),
|
||||
);
|
||||
|
||||
console.log(eventTable.toString() + '\n');
|
||||
|
||||
if (this.userDirectory) {
|
||||
await saveUserFile({
|
||||
fileName: instanceName + '.json',
|
||||
userDirectory: this.userDirectory,
|
||||
dataString: JSON.stringify(events, null, 2) + '\n',
|
||||
events,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -474,10 +320,10 @@ export class NodeEncryptedNotesService extends BaseEncryptedNotesService {
|
||||
console.log(eventTable.toString() + '\n');
|
||||
|
||||
if (this.userDirectory) {
|
||||
await saveUserFile({
|
||||
fileName: instanceName + '.json',
|
||||
await saveEvents<EncryptedNotesEvents>({
|
||||
name: instanceName,
|
||||
userDirectory: this.userDirectory,
|
||||
dataString: JSON.stringify(events, null, 2) + '\n',
|
||||
events,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -561,7 +407,7 @@ export class NodeGovernanceService extends BaseGovernanceService {
|
||||
};
|
||||
}
|
||||
|
||||
const savedEvents = await loadSavedEvents<AllGovernanceEvents>({
|
||||
const savedEvents = await loadSavedEvents<BaseGovernanceEventTypes>({
|
||||
name: this.getInstanceName(),
|
||||
userDirectory: this.userDirectory,
|
||||
deployedBlock: this.deployedBlock,
|
||||
@ -585,7 +431,7 @@ export class NodeGovernanceService extends BaseGovernanceService {
|
||||
};
|
||||
}
|
||||
|
||||
const cachedEvents = await loadCachedEvents<AllGovernanceEvents>({
|
||||
const cachedEvents = await loadCachedEvents<BaseGovernanceEventTypes>({
|
||||
name: this.getInstanceName(),
|
||||
cacheDirectory: this.cacheDirectory,
|
||||
deployedBlock: this.deployedBlock,
|
||||
@ -597,7 +443,7 @@ export class NodeGovernanceService extends BaseGovernanceService {
|
||||
return cachedEvents;
|
||||
}
|
||||
|
||||
async saveEvents({ events, lastBlock }: BaseEvents<AllGovernanceEvents>) {
|
||||
async saveEvents({ events, lastBlock }: BaseEvents<BaseGovernanceEventTypes>) {
|
||||
const instanceName = this.getInstanceName();
|
||||
|
||||
console.log('\ntotalEvents count - ', events.length);
|
||||
@ -625,10 +471,10 @@ export class NodeGovernanceService extends BaseGovernanceService {
|
||||
console.log(eventTable.toString() + '\n');
|
||||
|
||||
if (this.userDirectory) {
|
||||
await saveUserFile({
|
||||
fileName: instanceName + '.json',
|
||||
await saveEvents<BaseGovernanceEventTypes>({
|
||||
name: instanceName,
|
||||
userDirectory: this.userDirectory,
|
||||
dataString: JSON.stringify(events, null, 2) + '\n',
|
||||
events,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -770,10 +616,10 @@ export class NodeRegistryService extends BaseRegistryService {
|
||||
console.log(eventTable.toString() + '\n');
|
||||
|
||||
if (this.userDirectory) {
|
||||
await saveUserFile({
|
||||
fileName: instanceName + '.json',
|
||||
await saveEvents<RegistersEvents>({
|
||||
name: instanceName,
|
||||
userDirectory: this.userDirectory,
|
||||
dataString: JSON.stringify(events, null, 2) + '\n',
|
||||
events,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -48,12 +48,6 @@ export type GovernanceUndelegatedEvents = GovernanceEvents & {
|
||||
delegateFrom: string;
|
||||
};
|
||||
|
||||
export type AllGovernanceEvents =
|
||||
| GovernanceProposalCreatedEvents
|
||||
| GovernanceVotedEvents
|
||||
| GovernanceDelegatedEvents
|
||||
| GovernanceUndelegatedEvents;
|
||||
|
||||
export type RegistersEvents = MinimalEvents & RelayerParams;
|
||||
|
||||
export type DepositsEvents = MinimalEvents & {
|
||||
@ -70,11 +64,6 @@ export type WithdrawalsEvents = MinimalEvents & {
|
||||
timestamp: number;
|
||||
};
|
||||
|
||||
export type EchoEvents = MinimalEvents & {
|
||||
address: string;
|
||||
encryptedAccount: string;
|
||||
};
|
||||
|
||||
export type EncryptedNotesEvents = MinimalEvents & {
|
||||
encryptedNote: string;
|
||||
};
|
||||
|
@ -8,12 +8,6 @@ import type {
|
||||
WithdrawalsEvents,
|
||||
EncryptedNotesEvents,
|
||||
BatchGraphOnProgress,
|
||||
EchoEvents,
|
||||
AllGovernanceEvents,
|
||||
GovernanceProposalCreatedEvents,
|
||||
GovernanceVotedEvents,
|
||||
GovernanceDelegatedEvents,
|
||||
GovernanceUndelegatedEvents,
|
||||
} from '../events';
|
||||
import {
|
||||
_META,
|
||||
@ -23,8 +17,6 @@ import {
|
||||
GET_WITHDRAWALS,
|
||||
GET_NOTE_ACCOUNTS,
|
||||
GET_ENCRYPTED_NOTES,
|
||||
GET_ECHO_EVENTS,
|
||||
GET_GOVERNANCE_EVENTS,
|
||||
} from './queries';
|
||||
|
||||
export * from './queries';
|
||||
@ -651,7 +643,7 @@ export async function getNoteAccounts({
|
||||
subgraphName,
|
||||
query: GET_NOTE_ACCOUNTS,
|
||||
variables: {
|
||||
address: address.toLowerCase(),
|
||||
address,
|
||||
},
|
||||
fetchDataOptions,
|
||||
});
|
||||
@ -670,132 +662,6 @@ export async function getNoteAccounts({
|
||||
}
|
||||
}
|
||||
|
||||
export interface GraphEchoEvents {
|
||||
noteAccounts: {
|
||||
id: string;
|
||||
blockNumber: string;
|
||||
address: string;
|
||||
encryptedAccount: string;
|
||||
}[];
|
||||
_meta: {
|
||||
block: {
|
||||
number: number;
|
||||
};
|
||||
hasIndexingErrors: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface getGraphEchoEventsParams {
|
||||
graphApi: string;
|
||||
subgraphName: string;
|
||||
fromBlock: number;
|
||||
fetchDataOptions?: fetchDataOptions;
|
||||
onProgress?: BatchGraphOnProgress;
|
||||
}
|
||||
|
||||
export function getGraphEchoEvents({
|
||||
graphApi,
|
||||
subgraphName,
|
||||
fromBlock,
|
||||
fetchDataOptions,
|
||||
}: getGraphEchoEventsParams): Promise<GraphEchoEvents> {
|
||||
return queryGraph<GraphEchoEvents>({
|
||||
graphApi,
|
||||
subgraphName,
|
||||
query: GET_ECHO_EVENTS,
|
||||
variables: {
|
||||
first,
|
||||
fromBlock,
|
||||
},
|
||||
fetchDataOptions,
|
||||
});
|
||||
}
|
||||
|
||||
export async function getAllGraphEchoEvents({
|
||||
graphApi,
|
||||
subgraphName,
|
||||
fromBlock,
|
||||
fetchDataOptions,
|
||||
onProgress,
|
||||
}: getGraphEchoEventsParams): Promise<BaseGraphEvents<EchoEvents>> {
|
||||
try {
|
||||
const events = [];
|
||||
let lastSyncBlock = fromBlock;
|
||||
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
let {
|
||||
noteAccounts: result,
|
||||
_meta: {
|
||||
// eslint-disable-next-line prefer-const
|
||||
block: { number: currentBlock },
|
||||
},
|
||||
} = await getGraphEchoEvents({ graphApi, subgraphName, fromBlock, fetchDataOptions });
|
||||
|
||||
lastSyncBlock = currentBlock;
|
||||
|
||||
if (isEmptyArray(result)) {
|
||||
break;
|
||||
}
|
||||
|
||||
const [firstEvent] = result;
|
||||
const [lastEvent] = result.slice(-1);
|
||||
|
||||
if (typeof onProgress === 'function') {
|
||||
onProgress({
|
||||
type: 'EchoEvents',
|
||||
fromBlock: Number(firstEvent.blockNumber),
|
||||
toBlock: Number(lastEvent.blockNumber),
|
||||
count: result.length,
|
||||
});
|
||||
}
|
||||
|
||||
if (result.length < 900) {
|
||||
events.push(...result);
|
||||
break;
|
||||
}
|
||||
|
||||
result = result.filter(({ blockNumber }) => blockNumber !== lastEvent.blockNumber);
|
||||
fromBlock = Number(lastEvent.blockNumber);
|
||||
|
||||
events.push(...result);
|
||||
}
|
||||
|
||||
if (!events.length) {
|
||||
return {
|
||||
events: [],
|
||||
lastSyncBlock,
|
||||
};
|
||||
}
|
||||
|
||||
const result = events.map((e) => {
|
||||
const [transactionHash, logIndex] = e.id.split('-');
|
||||
|
||||
return {
|
||||
blockNumber: Number(e.blockNumber),
|
||||
logIndex: Number(logIndex),
|
||||
transactionHash: transactionHash,
|
||||
address: getAddress(e.address),
|
||||
encryptedAccount: e.encryptedAccount,
|
||||
};
|
||||
});
|
||||
|
||||
const [lastEvent] = result.slice(-1);
|
||||
|
||||
return {
|
||||
events: result,
|
||||
lastSyncBlock: lastEvent && lastEvent.blockNumber >= lastSyncBlock ? lastEvent.blockNumber + 1 : lastSyncBlock,
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('Error from getAllGraphEchoEvents query');
|
||||
console.log(err);
|
||||
return {
|
||||
events: [],
|
||||
lastSyncBlock: fromBlock,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export interface GraphEncryptedNotes {
|
||||
encryptedNotes: {
|
||||
blockNumber: string;
|
||||
@ -916,223 +782,3 @@ export async function getAllEncryptedNotes({
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export interface GraphGovernanceEvents {
|
||||
proposals: {
|
||||
blockNumber: number;
|
||||
logIndex: number;
|
||||
transactionHash: string;
|
||||
proposalId: number;
|
||||
proposer: string;
|
||||
target: string;
|
||||
startTime: number;
|
||||
endTime: number;
|
||||
description: string;
|
||||
}[];
|
||||
votes: {
|
||||
blockNumber: number;
|
||||
logIndex: number;
|
||||
transactionHash: string;
|
||||
proposalId: number;
|
||||
voter: string;
|
||||
support: boolean;
|
||||
votes: string;
|
||||
from: string;
|
||||
input: string;
|
||||
}[];
|
||||
delegates: {
|
||||
blockNumber: number;
|
||||
logIndex: number;
|
||||
transactionHash: string;
|
||||
account: string;
|
||||
delegateTo: string;
|
||||
}[];
|
||||
undelegates: {
|
||||
blockNumber: number;
|
||||
logIndex: number;
|
||||
transactionHash: string;
|
||||
account: string;
|
||||
delegateFrom: string;
|
||||
}[];
|
||||
_meta: {
|
||||
block: {
|
||||
number: number;
|
||||
};
|
||||
hasIndexingErrors: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface getGovernanceEventsParams {
|
||||
graphApi: string;
|
||||
subgraphName: string;
|
||||
fromBlock: number;
|
||||
fetchDataOptions?: fetchDataOptions;
|
||||
onProgress?: BatchGraphOnProgress;
|
||||
}
|
||||
|
||||
export function getGovernanceEvents({
|
||||
graphApi,
|
||||
subgraphName,
|
||||
fromBlock,
|
||||
fetchDataOptions,
|
||||
}: getGovernanceEventsParams): Promise<GraphGovernanceEvents> {
|
||||
return queryGraph<GraphGovernanceEvents>({
|
||||
graphApi,
|
||||
subgraphName,
|
||||
query: GET_GOVERNANCE_EVENTS,
|
||||
variables: {
|
||||
first,
|
||||
fromBlock,
|
||||
},
|
||||
fetchDataOptions,
|
||||
});
|
||||
}
|
||||
|
||||
export async function getAllGovernanceEvents({
|
||||
graphApi,
|
||||
subgraphName,
|
||||
fromBlock,
|
||||
fetchDataOptions,
|
||||
onProgress,
|
||||
}: getGovernanceEventsParams): Promise<BaseGraphEvents<AllGovernanceEvents>> {
|
||||
try {
|
||||
const result = [];
|
||||
|
||||
let lastSyncBlock = fromBlock;
|
||||
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const {
|
||||
proposals,
|
||||
votes,
|
||||
delegates,
|
||||
undelegates,
|
||||
_meta: {
|
||||
block: { number: currentBlock },
|
||||
},
|
||||
} = await getGovernanceEvents({ graphApi, subgraphName, fromBlock, fetchDataOptions });
|
||||
|
||||
lastSyncBlock = currentBlock;
|
||||
|
||||
const eventsLength = proposals.length + votes.length + delegates.length + undelegates.length;
|
||||
|
||||
if (eventsLength === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
const formattedProposals: GovernanceProposalCreatedEvents[] = proposals.map(
|
||||
({ blockNumber, logIndex, transactionHash, proposalId, proposer, target, startTime, endTime, description }) => {
|
||||
return {
|
||||
blockNumber: Number(blockNumber),
|
||||
logIndex: Number(logIndex),
|
||||
transactionHash,
|
||||
event: 'ProposalCreated',
|
||||
id: Number(proposalId),
|
||||
proposer: getAddress(proposer),
|
||||
target: getAddress(target),
|
||||
startTime: Number(startTime),
|
||||
endTime: Number(endTime),
|
||||
description,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
const formattedVotes: GovernanceVotedEvents[] = votes.map(
|
||||
({ blockNumber, logIndex, transactionHash, proposalId, voter, support, votes, from, input }) => {
|
||||
// Filter spammy txs
|
||||
if (!input || input.length > 2048) {
|
||||
input = '';
|
||||
}
|
||||
|
||||
return {
|
||||
blockNumber: Number(blockNumber),
|
||||
logIndex: Number(logIndex),
|
||||
transactionHash,
|
||||
event: 'Voted',
|
||||
proposalId: Number(proposalId),
|
||||
voter: getAddress(voter),
|
||||
support,
|
||||
votes,
|
||||
from: getAddress(from),
|
||||
input,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
const formattedDelegates: GovernanceDelegatedEvents[] = delegates.map(
|
||||
({ blockNumber, logIndex, transactionHash, account, delegateTo }) => {
|
||||
return {
|
||||
blockNumber: Number(blockNumber),
|
||||
logIndex: Number(logIndex),
|
||||
transactionHash,
|
||||
event: 'Delegated',
|
||||
account: getAddress(account),
|
||||
delegateTo: getAddress(delegateTo),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
const formattedUndelegates: GovernanceUndelegatedEvents[] = undelegates.map(
|
||||
({ blockNumber, logIndex, transactionHash, account, delegateFrom }) => {
|
||||
return {
|
||||
blockNumber: Number(blockNumber),
|
||||
logIndex: Number(logIndex),
|
||||
transactionHash,
|
||||
event: 'Undelegated',
|
||||
account: getAddress(account),
|
||||
delegateFrom: getAddress(delegateFrom),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
let formattedEvents = [
|
||||
...formattedProposals,
|
||||
...formattedVotes,
|
||||
...formattedDelegates,
|
||||
...formattedUndelegates,
|
||||
].sort((a, b) => {
|
||||
if (a.blockNumber === b.blockNumber) {
|
||||
return a.logIndex - b.logIndex;
|
||||
}
|
||||
return a.blockNumber - b.blockNumber;
|
||||
});
|
||||
|
||||
if (eventsLength < 900) {
|
||||
result.push(...formattedEvents);
|
||||
break;
|
||||
}
|
||||
|
||||
const [firstEvent] = formattedEvents;
|
||||
const [lastEvent] = formattedEvents.slice(-1);
|
||||
|
||||
if (typeof onProgress === 'function') {
|
||||
onProgress({
|
||||
type: 'Governance Events',
|
||||
fromBlock: Number(firstEvent.blockNumber),
|
||||
toBlock: Number(lastEvent.blockNumber),
|
||||
count: eventsLength,
|
||||
});
|
||||
}
|
||||
|
||||
formattedEvents = formattedEvents.filter(({ blockNumber }) => blockNumber !== lastEvent.blockNumber);
|
||||
|
||||
fromBlock = Number(lastEvent.blockNumber);
|
||||
|
||||
result.push(...formattedEvents);
|
||||
}
|
||||
|
||||
const [lastEvent] = result.slice(-1);
|
||||
|
||||
return {
|
||||
events: result,
|
||||
lastSyncBlock: lastEvent && lastEvent.blockNumber >= lastSyncBlock ? lastEvent.blockNumber + 1 : lastSyncBlock,
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('Error from getAllGovernance query');
|
||||
console.log(err);
|
||||
return {
|
||||
events: [],
|
||||
lastSyncBlock: fromBlock,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -107,23 +107,6 @@ export const GET_NOTE_ACCOUNTS = `
|
||||
}
|
||||
`;
|
||||
|
||||
export const GET_ECHO_EVENTS = `
|
||||
query getNoteAccounts($first: Int, $fromBlock: Int) {
|
||||
noteAccounts(first: $first, orderBy: blockNumber, orderDirection: asc, where: { blockNumber_gte: $fromBlock }) {
|
||||
id
|
||||
blockNumber
|
||||
address
|
||||
encryptedAccount
|
||||
}
|
||||
_meta {
|
||||
block {
|
||||
number
|
||||
}
|
||||
hasIndexingErrors
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const GET_ENCRYPTED_NOTES = `
|
||||
query getEncryptedNotes($first: Int, $fromBlock: Int) {
|
||||
encryptedNotes(first: $first, orderBy: blockNumber, orderDirection: asc, where: { blockNumber_gte: $fromBlock }) {
|
||||
@ -140,58 +123,3 @@ export const GET_ENCRYPTED_NOTES = `
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const GET_GOVERNANCE_EVENTS = `
|
||||
query getGovernanceEvents($first: Int, $fromBlock: Int) {
|
||||
proposals(first: $first, orderBy: blockNumber, orderDirection: asc, where: { blockNumber_gte: $fromBlock }) {
|
||||
blockNumber
|
||||
logIndex
|
||||
transactionHash
|
||||
proposalId
|
||||
proposer
|
||||
target
|
||||
startTime
|
||||
endTime
|
||||
description
|
||||
}
|
||||
votes(first: $first, orderBy: blockNumber, orderDirection: asc, where: { blockNumber_gte: $fromBlock }) {
|
||||
blockNumber
|
||||
logIndex
|
||||
transactionHash
|
||||
proposalId
|
||||
voter
|
||||
support
|
||||
votes
|
||||
from
|
||||
input
|
||||
}
|
||||
delegates(first: $first, orderBy: blockNumber, orderDirection: asc, where: { blockNumber_gte: $fromBlock }) {
|
||||
blockNumber
|
||||
logIndex
|
||||
transactionHash
|
||||
account
|
||||
delegateTo
|
||||
}
|
||||
undelegates(first: $first, orderBy: blockNumber, orderDirection: asc, where: { blockNumber_gte: $fromBlock }) {
|
||||
blockNumber
|
||||
logIndex
|
||||
transactionHash
|
||||
account
|
||||
delegateFrom
|
||||
}
|
||||
_meta {
|
||||
block {
|
||||
number
|
||||
}
|
||||
hasIndexingErrors
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const GET_GOVERNANCE_APY = `
|
||||
stakeDailyBurns(first: 30, orderBy: date, orderDirection: desc) {
|
||||
id
|
||||
date
|
||||
dailyAmountBurned
|
||||
}
|
||||
`;
|
||||
|
@ -4,7 +4,6 @@ export * from './schemas';
|
||||
export * from './batch';
|
||||
export * from './data';
|
||||
export * from './deposits';
|
||||
export * from './encryptedNotes';
|
||||
export * from './fees';
|
||||
export * from './merkleTree';
|
||||
export * from './mimc';
|
||||
@ -16,6 +15,5 @@ export * from './prices';
|
||||
export * from './providers';
|
||||
export * from './relayerClient';
|
||||
export * from './tokens';
|
||||
export * from './treeCache';
|
||||
export * from './utils';
|
||||
export * from './websnark';
|
||||
|
@ -1,15 +1,14 @@
|
||||
import { Worker as NodeWorker } from 'worker_threads';
|
||||
import { MerkleTree, PartialMerkleTree, Element, TreeEdge } from '@tornado/fixed-merkle-tree';
|
||||
import { MerkleTree, Element } from '@tornado/fixed-merkle-tree';
|
||||
import type { Tornado } from '@tornado/contracts';
|
||||
import { isNode, toFixedHex } from './utils';
|
||||
import { mimc } from './mimc';
|
||||
import type { DepositType } from './deposits';
|
||||
import type { DepositsEvents } from './events';
|
||||
import type { NetIdType } from './networkConfig';
|
||||
|
||||
export type MerkleTreeConstructor = DepositType & {
|
||||
Tornado: Tornado;
|
||||
commitmentHex?: string;
|
||||
commitment?: string;
|
||||
merkleTreeHeight?: number;
|
||||
emptyElement?: string;
|
||||
merkleWorkerPath?: string;
|
||||
@ -18,9 +17,9 @@ export type MerkleTreeConstructor = DepositType & {
|
||||
export class MerkleTreeService {
|
||||
currency: string;
|
||||
amount: string;
|
||||
netId: NetIdType;
|
||||
netId: number;
|
||||
Tornado: Tornado;
|
||||
commitmentHex?: string;
|
||||
commitment?: string;
|
||||
instanceName: string;
|
||||
|
||||
merkleTreeHeight: number;
|
||||
@ -33,7 +32,7 @@ export class MerkleTreeService {
|
||||
amount,
|
||||
currency,
|
||||
Tornado,
|
||||
commitmentHex,
|
||||
commitment,
|
||||
merkleTreeHeight = 20,
|
||||
emptyElement = '21663839004416932945382355908790599225266501822907911457504978515578255421292',
|
||||
merkleWorkerPath,
|
||||
@ -46,14 +45,14 @@ export class MerkleTreeService {
|
||||
|
||||
this.Tornado = Tornado;
|
||||
this.instanceName = instanceName;
|
||||
this.commitmentHex = commitmentHex;
|
||||
this.commitment = commitment;
|
||||
|
||||
this.merkleTreeHeight = merkleTreeHeight;
|
||||
this.emptyElement = emptyElement;
|
||||
this.merkleWorkerPath = merkleWorkerPath;
|
||||
}
|
||||
|
||||
async createTree(events: Element[]) {
|
||||
async createTree({ events }: { events: Element[] }) {
|
||||
const { hash: hashFunction } = await mimc.getHash();
|
||||
|
||||
if (this.merkleWorkerPath) {
|
||||
@ -114,76 +113,13 @@ export class MerkleTreeService {
|
||||
});
|
||||
}
|
||||
|
||||
async createPartialTree({ edge, elements }: { edge: TreeEdge; elements: Element[] }) {
|
||||
const { hash: hashFunction } = await mimc.getHash();
|
||||
|
||||
if (this.merkleWorkerPath) {
|
||||
console.log('Using merkleWorker\n');
|
||||
|
||||
try {
|
||||
if (isNode) {
|
||||
const merkleWorkerPromise = new Promise((resolve, reject) => {
|
||||
const worker = new NodeWorker(this.merkleWorkerPath as string, {
|
||||
workerData: {
|
||||
merkleTreeHeight: this.merkleTreeHeight,
|
||||
edge,
|
||||
elements,
|
||||
zeroElement: this.emptyElement,
|
||||
},
|
||||
});
|
||||
worker.on('message', resolve);
|
||||
worker.on('error', reject);
|
||||
worker.on('exit', (code) => {
|
||||
if (code !== 0) {
|
||||
reject(new Error(`Worker stopped with exit code ${code}`));
|
||||
}
|
||||
});
|
||||
}) as Promise<string>;
|
||||
|
||||
return PartialMerkleTree.deserialize(JSON.parse(await merkleWorkerPromise), hashFunction);
|
||||
} else {
|
||||
const merkleWorkerPromise = new Promise((resolve, reject) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const worker = new (Worker as any)(this.merkleWorkerPath);
|
||||
|
||||
worker.onmessage = (e: { data: string }) => {
|
||||
resolve(e.data);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
worker.onerror = (e: any) => {
|
||||
reject(e);
|
||||
};
|
||||
|
||||
worker.postMessage({
|
||||
merkleTreeHeight: this.merkleTreeHeight,
|
||||
edge,
|
||||
elements,
|
||||
zeroElement: this.emptyElement,
|
||||
});
|
||||
}) as Promise<string>;
|
||||
|
||||
return PartialMerkleTree.deserialize(JSON.parse(await merkleWorkerPromise), hashFunction);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('merkleWorker failed, falling back to synchronous merkle tree');
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
return new PartialMerkleTree(this.merkleTreeHeight, edge, elements, {
|
||||
zeroElement: this.emptyElement,
|
||||
hashFunction,
|
||||
});
|
||||
}
|
||||
|
||||
async verifyTree(events: DepositsEvents[]) {
|
||||
async verifyTree({ events }: { events: DepositsEvents[] }) {
|
||||
console.log(
|
||||
`\nCreating deposit tree for ${this.netId} ${this.amount} ${this.currency.toUpperCase()} would take a while\n`,
|
||||
);
|
||||
|
||||
console.time('Created tree in');
|
||||
const tree = await this.createTree(events.map(({ commitment }) => commitment));
|
||||
const tree = await this.createTree({ events: events.map(({ commitment }) => BigInt(commitment).toString()) });
|
||||
console.timeEnd('Created tree in');
|
||||
console.log('');
|
||||
|
||||
|
@ -1,19 +1,3 @@
|
||||
/**
|
||||
* Type of default supported networks
|
||||
*/
|
||||
export enum NetId {
|
||||
MAINNET = 1,
|
||||
BSC = 56,
|
||||
POLYGON = 137,
|
||||
OPTIMISM = 10,
|
||||
ARBITRUM = 42161,
|
||||
GNOSIS = 100,
|
||||
AVALANCHE = 43114,
|
||||
SEPOLIA = 11155111,
|
||||
}
|
||||
|
||||
export type NetIdType = NetId | number;
|
||||
|
||||
export interface RpcUrl {
|
||||
name: string;
|
||||
url: string;
|
||||
@ -62,20 +46,20 @@ export type Config = {
|
||||
};
|
||||
nativeCurrency: string;
|
||||
currencyName: string;
|
||||
explorerUrl: string;
|
||||
explorerUrl: {
|
||||
tx: string;
|
||||
address: string;
|
||||
block: string;
|
||||
};
|
||||
merkleTreeHeight: number;
|
||||
emptyElement: string;
|
||||
networkName: string;
|
||||
deployedBlock: number;
|
||||
rpcUrls: RpcUrls;
|
||||
multicallContract: string;
|
||||
multicall: string;
|
||||
routerContract: string;
|
||||
echoContract: string;
|
||||
offchainOracleContract?: string;
|
||||
tornContract?: string;
|
||||
governanceContract?: string;
|
||||
stakingRewardsContract?: string;
|
||||
registryContract?: string;
|
||||
echoContract: string;
|
||||
aggregatorContract?: string;
|
||||
reverseRecordsContract?: string;
|
||||
gasPriceOracleContract?: string;
|
||||
@ -83,7 +67,6 @@ export type Config = {
|
||||
ovmGasPriceOracleContract?: string;
|
||||
tornadoSubgraph: string;
|
||||
registrySubgraph?: string;
|
||||
governanceSubgraph?: string;
|
||||
subgraphs: SubgraphUrls;
|
||||
tokens: TokenInstances;
|
||||
optionalTokens?: string[];
|
||||
@ -98,12 +81,20 @@ export type Config = {
|
||||
// Should be in seconds
|
||||
MINING_BLOCK_TIME?: number;
|
||||
};
|
||||
'torn.contract.tornadocash.eth'?: string;
|
||||
'governance.contract.tornadocash.eth'?: string;
|
||||
'staking-rewards.contract.tornadocash.eth'?: string;
|
||||
'tornado-router.contract.tornadocash.eth'?: string;
|
||||
'tornado-proxy-light.contract.tornadocash.eth'?: string;
|
||||
};
|
||||
|
||||
export type networkConfig = {
|
||||
[key in NetIdType]: Config;
|
||||
[key in string]: Config;
|
||||
};
|
||||
|
||||
export const blockSyncInterval = 10000;
|
||||
export const enabledChains = ['1', '10', '56', '100', '137', '42161', '43114', '11155111'];
|
||||
|
||||
const theGraph = {
|
||||
name: 'Hosted Graph',
|
||||
url: 'https://api.thegraph.com',
|
||||
@ -113,8 +104,8 @@ const tornado = {
|
||||
url: 'https://tornadocash-rpc.com',
|
||||
};
|
||||
|
||||
export const defaultConfig: networkConfig = {
|
||||
[NetId.MAINNET]: {
|
||||
export const networkConfig: networkConfig = {
|
||||
netId1: {
|
||||
rpcCallRetryAttempt: 15,
|
||||
gasPrices: {
|
||||
instant: 80,
|
||||
@ -124,7 +115,11 @@ export const defaultConfig: networkConfig = {
|
||||
},
|
||||
nativeCurrency: 'eth',
|
||||
currencyName: 'ETH',
|
||||
explorerUrl: 'https://etherscan.io',
|
||||
explorerUrl: {
|
||||
tx: 'https://etherscan.io/tx/',
|
||||
address: 'https://etherscan.io/address/',
|
||||
block: 'https://etherscan.io/block/',
|
||||
},
|
||||
merkleTreeHeight: 20,
|
||||
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
|
||||
networkName: 'Ethereum Mainnet',
|
||||
@ -135,7 +130,7 @@ export const defaultConfig: networkConfig = {
|
||||
url: 'https://tornadocash-rpc.com',
|
||||
},
|
||||
chainnodes: {
|
||||
name: 'Chainnodes RPC',
|
||||
name: 'Tornado RPC',
|
||||
url: 'https://mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607',
|
||||
},
|
||||
mevblockerRPC: {
|
||||
@ -163,19 +158,14 @@ export const defaultConfig: networkConfig = {
|
||||
url: 'https://1rpc.io/eth',
|
||||
},
|
||||
},
|
||||
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
||||
multicall: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
||||
routerContract: '0xd90e2f925DA726b50C4Ed8D0Fb90Ad053324F31b',
|
||||
echoContract: '0x9B27DD5Bb15d42DC224FCD0B7caEbBe16161Df42',
|
||||
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
||||
tornContract: '0x77777FeDdddFfC19Ff86DB637967013e6C6A116C',
|
||||
governanceContract: '0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce',
|
||||
stakingRewardsContract: '0x5B3f656C80E8ddb9ec01Dd9018815576E9238c29',
|
||||
registryContract: '0x58E8dCC13BE9780fC42E8723D8EaD4CF46943dF2',
|
||||
echoContract: '0x9B27DD5Bb15d42DC224FCD0B7caEbBe16161Df42',
|
||||
aggregatorContract: '0xE8F47A78A6D52D317D0D2FFFac56739fE14D1b49',
|
||||
reverseRecordsContract: '0x3671aE578E63FdF66ad4F3E12CC0c0d71Ac7510C',
|
||||
tornadoSubgraph: 'tornadocash/mainnet-tornado-subgraph',
|
||||
registrySubgraph: 'tornadocash/tornado-relayer-registry',
|
||||
governanceSubgraph: 'tornadocash/tornado-governance',
|
||||
subgraphs: {
|
||||
tornado,
|
||||
theGraph,
|
||||
@ -257,12 +247,16 @@ export const defaultConfig: networkConfig = {
|
||||
constants: {
|
||||
GOVERNANCE_BLOCK: 11474695,
|
||||
NOTE_ACCOUNT_BLOCK: 11842486,
|
||||
ENCRYPTED_NOTES_BLOCK: 12143762,
|
||||
ENCRYPTED_NOTES_BLOCK: 14248730,
|
||||
REGISTRY_BLOCK: 14173129,
|
||||
MINING_BLOCK_TIME: 15,
|
||||
},
|
||||
'torn.contract.tornadocash.eth': '0x77777FeDdddFfC19Ff86DB637967013e6C6A116C',
|
||||
'governance.contract.tornadocash.eth': '0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce',
|
||||
'tornado-router.contract.tornadocash.eth': '0xd90e2f925DA726b50C4Ed8D0Fb90Ad053324F31b',
|
||||
'staking-rewards.contract.tornadocash.eth': '0x5B3f656C80E8ddb9ec01Dd9018815576E9238c29',
|
||||
},
|
||||
[NetId.BSC]: {
|
||||
netId56: {
|
||||
rpcCallRetryAttempt: 15,
|
||||
gasPrices: {
|
||||
instant: 5,
|
||||
@ -272,15 +266,18 @@ export const defaultConfig: networkConfig = {
|
||||
},
|
||||
nativeCurrency: 'bnb',
|
||||
currencyName: 'BNB',
|
||||
explorerUrl: 'https://bscscan.com',
|
||||
explorerUrl: {
|
||||
tx: 'https://bscscan.com/tx/',
|
||||
address: 'https://bscscan.com/address/',
|
||||
block: 'https://bscscan.com/block/',
|
||||
},
|
||||
merkleTreeHeight: 20,
|
||||
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
|
||||
networkName: 'Binance Smart Chain',
|
||||
deployedBlock: 8158799,
|
||||
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
||||
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
multicall: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
||||
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
||||
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
tornadoSubgraph: 'tornadocash/bsc-tornado-subgraph',
|
||||
subgraphs: {
|
||||
tornado,
|
||||
@ -292,7 +289,7 @@ export const defaultConfig: networkConfig = {
|
||||
url: 'https://tornadocash-rpc.com/bsc',
|
||||
},
|
||||
chainnodes: {
|
||||
name: 'Chainnodes RPC',
|
||||
name: 'Tornado RPC',
|
||||
url: 'https://bsc-mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607',
|
||||
},
|
||||
stackup: {
|
||||
@ -326,8 +323,9 @@ export const defaultConfig: networkConfig = {
|
||||
NOTE_ACCOUNT_BLOCK: 8159269,
|
||||
ENCRYPTED_NOTES_BLOCK: 8159269,
|
||||
},
|
||||
'tornado-proxy-light.contract.tornadocash.eth': '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
},
|
||||
[NetId.POLYGON]: {
|
||||
netId137: {
|
||||
rpcCallRetryAttempt: 15,
|
||||
gasPrices: {
|
||||
instant: 100,
|
||||
@ -337,15 +335,18 @@ export const defaultConfig: networkConfig = {
|
||||
},
|
||||
nativeCurrency: 'matic',
|
||||
currencyName: 'MATIC',
|
||||
explorerUrl: 'https://polygonscan.com',
|
||||
explorerUrl: {
|
||||
tx: 'https://polygonscan.com/tx/',
|
||||
address: 'https://polygonscan.com/address/',
|
||||
block: 'https://polygonscan.com/block/',
|
||||
},
|
||||
merkleTreeHeight: 20,
|
||||
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
|
||||
networkName: 'Polygon (Matic) Network',
|
||||
deployedBlock: 16257962,
|
||||
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
||||
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
multicall: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
||||
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
||||
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
gasPriceOracleContract: '0xF81A8D8D3581985D3969fe53bFA67074aDFa8F3C',
|
||||
tornadoSubgraph: 'tornadocash/matic-tornado-subgraph',
|
||||
subgraphs: {
|
||||
@ -384,8 +385,9 @@ export const defaultConfig: networkConfig = {
|
||||
NOTE_ACCOUNT_BLOCK: 16257996,
|
||||
ENCRYPTED_NOTES_BLOCK: 16257996,
|
||||
},
|
||||
'tornado-proxy-light.contract.tornadocash.eth': '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
},
|
||||
[NetId.OPTIMISM]: {
|
||||
netId10: {
|
||||
rpcCallRetryAttempt: 15,
|
||||
gasPrices: {
|
||||
instant: 0.001,
|
||||
@ -395,15 +397,18 @@ export const defaultConfig: networkConfig = {
|
||||
},
|
||||
nativeCurrency: 'eth',
|
||||
currencyName: 'ETH',
|
||||
explorerUrl: 'https://optimistic.etherscan.io',
|
||||
explorerUrl: {
|
||||
tx: 'https://optimistic.etherscan.io/tx/',
|
||||
address: 'https://optimistic.etherscan.io/address/',
|
||||
block: 'https://optimistic.etherscan.io/block/',
|
||||
},
|
||||
merkleTreeHeight: 20,
|
||||
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
|
||||
networkName: 'Optimism',
|
||||
deployedBlock: 2243689,
|
||||
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
||||
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
multicall: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
||||
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
||||
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
ovmGasPriceOracleContract: '0x420000000000000000000000000000000000000F',
|
||||
tornadoSubgraph: 'tornadocash/optimism-tornado-subgraph',
|
||||
subgraphs: {
|
||||
@ -416,7 +421,7 @@ export const defaultConfig: networkConfig = {
|
||||
url: 'https://tornadocash-rpc.com/op',
|
||||
},
|
||||
chainnodes: {
|
||||
name: 'Chainnodes RPC',
|
||||
name: 'Tornado RPC',
|
||||
url: 'https://optimism-mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607',
|
||||
},
|
||||
optimism: {
|
||||
@ -450,8 +455,9 @@ export const defaultConfig: networkConfig = {
|
||||
NOTE_ACCOUNT_BLOCK: 2243694,
|
||||
ENCRYPTED_NOTES_BLOCK: 2243694,
|
||||
},
|
||||
'tornado-proxy-light.contract.tornadocash.eth': '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
},
|
||||
[NetId.ARBITRUM]: {
|
||||
netId42161: {
|
||||
rpcCallRetryAttempt: 15,
|
||||
gasPrices: {
|
||||
instant: 4,
|
||||
@ -461,15 +467,18 @@ export const defaultConfig: networkConfig = {
|
||||
},
|
||||
nativeCurrency: 'eth',
|
||||
currencyName: 'ETH',
|
||||
explorerUrl: 'https://arbiscan.io',
|
||||
explorerUrl: {
|
||||
tx: 'https://arbiscan.io/tx/',
|
||||
address: 'https://arbiscan.io/address/',
|
||||
block: 'https://arbiscan.io/block/',
|
||||
},
|
||||
merkleTreeHeight: 20,
|
||||
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
|
||||
networkName: 'Arbitrum One',
|
||||
deployedBlock: 3430648,
|
||||
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
||||
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
multicall: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
||||
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
||||
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
tornadoSubgraph: 'tornadocash/arbitrum-tornado-subgraph',
|
||||
subgraphs: {
|
||||
tornado,
|
||||
@ -481,7 +490,7 @@ export const defaultConfig: networkConfig = {
|
||||
url: 'https://tornadocash-rpc.com/arbitrum',
|
||||
},
|
||||
chainnodes: {
|
||||
name: 'Chainnodes RPC',
|
||||
name: 'Tornado RPC',
|
||||
url: 'https://arbitrum-one.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607',
|
||||
},
|
||||
arbitrum: {
|
||||
@ -515,8 +524,9 @@ export const defaultConfig: networkConfig = {
|
||||
NOTE_ACCOUNT_BLOCK: 3430605,
|
||||
ENCRYPTED_NOTES_BLOCK: 3430605,
|
||||
},
|
||||
'tornado-proxy-light.contract.tornadocash.eth': '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
},
|
||||
[NetId.GNOSIS]: {
|
||||
netId100: {
|
||||
rpcCallRetryAttempt: 15,
|
||||
gasPrices: {
|
||||
instant: 6,
|
||||
@ -526,15 +536,18 @@ export const defaultConfig: networkConfig = {
|
||||
},
|
||||
nativeCurrency: 'xdai',
|
||||
currencyName: 'xDAI',
|
||||
explorerUrl: 'https://gnosisscan.io',
|
||||
explorerUrl: {
|
||||
tx: 'https://blockscout.com/xdai/mainnet/tx/',
|
||||
address: 'https://blockscout.com/xdai/mainnet/address/',
|
||||
block: 'https://blockscout.com/xdai/mainnet/block/',
|
||||
},
|
||||
merkleTreeHeight: 20,
|
||||
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
|
||||
networkName: 'Gnosis Chain',
|
||||
deployedBlock: 17754561,
|
||||
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
||||
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
multicall: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
||||
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
||||
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
tornadoSubgraph: 'tornadocash/xdai-tornado-subgraph',
|
||||
subgraphs: {
|
||||
tornado,
|
||||
@ -546,7 +559,7 @@ export const defaultConfig: networkConfig = {
|
||||
url: 'https://tornadocash-rpc.com/gnosis',
|
||||
},
|
||||
chainnodes: {
|
||||
name: 'Chainnodes RPC',
|
||||
name: 'Tornado RPC',
|
||||
url: 'https://gnosis-mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607',
|
||||
},
|
||||
gnosis: {
|
||||
@ -580,8 +593,9 @@ export const defaultConfig: networkConfig = {
|
||||
NOTE_ACCOUNT_BLOCK: 17754564,
|
||||
ENCRYPTED_NOTES_BLOCK: 17754564,
|
||||
},
|
||||
'tornado-proxy-light.contract.tornadocash.eth': '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
},
|
||||
[NetId.AVALANCHE]: {
|
||||
netId43114: {
|
||||
rpcCallRetryAttempt: 15,
|
||||
gasPrices: {
|
||||
instant: 225,
|
||||
@ -591,15 +605,18 @@ export const defaultConfig: networkConfig = {
|
||||
},
|
||||
nativeCurrency: 'avax',
|
||||
currencyName: 'AVAX',
|
||||
explorerUrl: 'https://snowtrace.io',
|
||||
explorerUrl: {
|
||||
tx: 'https://snowtrace.io/tx/',
|
||||
address: 'https://snowtrace.io/address/',
|
||||
block: 'https://snowtrace.io/block/',
|
||||
},
|
||||
merkleTreeHeight: 20,
|
||||
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
|
||||
networkName: 'Avalanche Mainnet',
|
||||
deployedBlock: 4429818,
|
||||
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
||||
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
multicall: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
||||
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||
offchainOracleContract: '0x0AdDd25a91563696D8567Df78D5A01C9a991F9B8',
|
||||
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
tornadoSubgraph: 'tornadocash/avalanche-tornado-subgraph',
|
||||
subgraphs: {
|
||||
theGraph,
|
||||
@ -635,8 +652,9 @@ export const defaultConfig: networkConfig = {
|
||||
NOTE_ACCOUNT_BLOCK: 4429813,
|
||||
ENCRYPTED_NOTES_BLOCK: 4429813,
|
||||
},
|
||||
'tornado-proxy-light.contract.tornadocash.eth': '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
|
||||
},
|
||||
[NetId.SEPOLIA]: {
|
||||
netId11155111: {
|
||||
rpcCallRetryAttempt: 15,
|
||||
gasPrices: {
|
||||
instant: 2,
|
||||
@ -646,18 +664,19 @@ export const defaultConfig: networkConfig = {
|
||||
},
|
||||
nativeCurrency: 'eth',
|
||||
currencyName: 'SepoliaETH',
|
||||
explorerUrl: 'https://sepolia.etherscan.io',
|
||||
explorerUrl: {
|
||||
tx: 'https://sepolia.etherscan.io/tx/',
|
||||
address: 'https://sepolia.etherscan.io/address/',
|
||||
block: 'https://sepolia.etherscan.io/block/',
|
||||
},
|
||||
merkleTreeHeight: 20,
|
||||
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
|
||||
networkName: 'Ethereum Sepolia',
|
||||
deployedBlock: 5594395,
|
||||
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
||||
multicall: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
||||
routerContract: '0x1572AFE6949fdF51Cb3E0856216670ae9Ee160Ee',
|
||||
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||
tornContract: '0x3AE6667167C0f44394106E197904519D808323cA',
|
||||
governanceContract: '0xe5324cD7602eeb387418e594B87aCADee08aeCAD',
|
||||
stakingRewardsContract: '0x6d0018890751Efd31feb8166711B16732E2b496b',
|
||||
registryContract: '0x1428e5d2356b13778A13108b10c440C83011dfB8',
|
||||
echoContract: '0xcDD1fc3F5ac2782D83449d3AbE80D6b7B273B0e5',
|
||||
aggregatorContract: '0x4088712AC9fad39ea133cdb9130E465d235e9642',
|
||||
reverseRecordsContract: '0xEc29700C0283e5Be64AcdFe8077d6cC95dE23C23',
|
||||
tornadoSubgraph: 'tornadocash/sepolia-tornado-subgraph',
|
||||
@ -711,80 +730,12 @@ export const defaultConfig: networkConfig = {
|
||||
ENCRYPTED_NOTES_BLOCK: 5594395,
|
||||
MINING_BLOCK_TIME: 15,
|
||||
},
|
||||
'torn.contract.tornadocash.eth': '0x3AE6667167C0f44394106E197904519D808323cA',
|
||||
'governance.contract.tornadocash.eth': '0xe5324cD7602eeb387418e594B87aCADee08aeCAD',
|
||||
'tornado-router.contract.tornadocash.eth': '0x1572AFE6949fdF51Cb3E0856216670ae9Ee160Ee',
|
||||
},
|
||||
};
|
||||
|
||||
export const enabledChains = Object.values(NetId).filter((n) => typeof n === 'number') as NetIdType[];
|
||||
export const subdomains = enabledChains.map((chain) => networkConfig[`netId${chain}`].ensSubdomainKey);
|
||||
|
||||
/**
|
||||
* Custom config object to extend default config
|
||||
*
|
||||
* Inspired by getUrlFunc from ethers.js
|
||||
* https://github.com/ethers-io/ethers.js/blob/v6/src.ts/utils/fetch.ts#L59
|
||||
*/
|
||||
export let customConfig: networkConfig = {};
|
||||
|
||||
/**
|
||||
* Add or override existing network config object
|
||||
*
|
||||
* Could be also called on the UI hook so that the UI could allow people to use custom privacy pools
|
||||
*/
|
||||
export function addNetwork(newConfig: networkConfig) {
|
||||
enabledChains.push(
|
||||
...Object.keys(newConfig)
|
||||
.map((netId) => Number(netId))
|
||||
.filter((netId) => !enabledChains.includes(netId)),
|
||||
);
|
||||
|
||||
customConfig = {
|
||||
...customConfig,
|
||||
...newConfig,
|
||||
};
|
||||
}
|
||||
|
||||
export function getNetworkConfig(): networkConfig {
|
||||
// customConfig object
|
||||
const allConfig = {
|
||||
...defaultConfig,
|
||||
...customConfig,
|
||||
};
|
||||
|
||||
return enabledChains.reduce((acc, curr) => {
|
||||
acc[curr] = allConfig[curr];
|
||||
return acc;
|
||||
}, {} as networkConfig);
|
||||
}
|
||||
|
||||
export function getConfig(netId: NetIdType) {
|
||||
const allConfig = getNetworkConfig();
|
||||
|
||||
const chainConfig = allConfig[netId];
|
||||
|
||||
if (!chainConfig) {
|
||||
const errMsg = `No config found for network ${netId}!`;
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
|
||||
return chainConfig;
|
||||
}
|
||||
|
||||
export function getInstanceByAddress({ netId, address }: { netId: NetIdType; address: string }) {
|
||||
const { tokens } = getConfig(netId);
|
||||
|
||||
for (const [currency, { instanceAddress }] of Object.entries(tokens)) {
|
||||
for (const [amount, instance] of Object.entries(instanceAddress)) {
|
||||
if (instance === address) {
|
||||
return {
|
||||
amount,
|
||||
currency,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getSubdomains() {
|
||||
const allConfig = getNetworkConfig();
|
||||
|
||||
return enabledChains.map((chain) => allConfig[chain].ensSubdomainKey);
|
||||
}
|
||||
export default networkConfig;
|
||||
|
@ -60,18 +60,3 @@ export function parseKey(value?: string): string {
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recovery key shouldn't have a 0x prefix (Also this is how the UI generates)
|
||||
*/
|
||||
export function parseRecoveryKey(value?: string): string {
|
||||
if (!value) {
|
||||
throw new InvalidArgumentError('Invalid Recovery Key');
|
||||
}
|
||||
try {
|
||||
computeAddress('0x' + value);
|
||||
} catch {
|
||||
throw new InvalidArgumentError('Invalid Recovery Key');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import {
|
||||
Network,
|
||||
parseUnits,
|
||||
FetchUrlFeeDataNetworkPlugin,
|
||||
BigNumberish,
|
||||
FeeData,
|
||||
EnsPlugin,
|
||||
GasCostPlugin,
|
||||
@ -29,7 +30,7 @@ import {
|
||||
import type { RequestInfo, RequestInit, Response, HeadersInit } from 'node-fetch';
|
||||
import { GasPriceOracle, GasPriceOracle__factory, Multicall, Multicall__factory } from '../typechain';
|
||||
import { isNode, sleep } from './utils';
|
||||
import type { Config, NetIdType } from './networkConfig';
|
||||
import type { Config } from './networkConfig';
|
||||
import { multicall } from './multicall';
|
||||
|
||||
declare global {
|
||||
@ -212,7 +213,7 @@ export async function fetchData(url: string, options: fetchDataOptions = {}) {
|
||||
throw errorObject;
|
||||
}
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable prettier/prettier, @typescript-eslint/no-explicit-any */
|
||||
export const fetchGetUrlFunc =
|
||||
(options: fetchDataOptions = {}): FetchGetUrlFunc =>
|
||||
async (req, _signal) => {
|
||||
@ -252,7 +253,7 @@ export const fetchGetUrlFunc =
|
||||
body,
|
||||
};
|
||||
};
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-enable prettier/prettier, @typescript-eslint/no-explicit-any */
|
||||
|
||||
// caching to improve performance
|
||||
const oracleMapper = new Map();
|
||||
@ -365,7 +366,7 @@ export async function getProvider(rpcUrl: string, fetchOptions?: getProviderOpti
|
||||
}
|
||||
|
||||
export function getProviderWithNetId(
|
||||
netId: NetIdType,
|
||||
netId: BigNumberish,
|
||||
rpcUrl: string,
|
||||
config: Config,
|
||||
fetchOptions?: getProviderOptions,
|
||||
@ -603,7 +604,7 @@ export type handleWalletFunc = (...args: any[]) => void;
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
|
||||
export type TornadoBrowserProviderOptions = TornadoWalletOptions & {
|
||||
webChainId?: NetIdType;
|
||||
webChainId?: BigNumberish;
|
||||
connectWallet?: connectWalletFunc;
|
||||
handleNetworkChanges?: handleWalletFunc;
|
||||
handleAccountChanges?: handleWalletFunc;
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { getAddress, namehash, parseEther } from 'ethers';
|
||||
import { namehash, parseEther } from 'ethers';
|
||||
import type { Aggregator } from '@tornado/contracts';
|
||||
import type { RelayerStructOutput } from '@tornado/contracts/dist/contracts/Governance/Aggregator/Aggregator';
|
||||
import { sleep } from './utils';
|
||||
import { NetId, NetIdType, Config } from './networkConfig';
|
||||
import type { Config } from './networkConfig';
|
||||
import { fetchData, fetchDataOptions } from './providers';
|
||||
import { ajv, jobsSchema, getStatusSchema } from './schemas';
|
||||
import type { snarkProofs } from './websnark';
|
||||
@ -15,23 +15,21 @@ export interface RelayerParams {
|
||||
}
|
||||
|
||||
export interface Relayer {
|
||||
netId: NetIdType;
|
||||
netId: number;
|
||||
url: string;
|
||||
hostname: string;
|
||||
rewardAccount: string;
|
||||
instances: string[];
|
||||
gasPrice?: number;
|
||||
ethPrices?: {
|
||||
[key in string]: string;
|
||||
};
|
||||
currentQueue: number;
|
||||
tornadoServiceFee: number;
|
||||
}
|
||||
|
||||
export type RelayerInfo = Relayer & {
|
||||
hostname: string;
|
||||
ensName: string;
|
||||
stakeBalance: bigint;
|
||||
relayerAddress: string;
|
||||
ethPrices?: {
|
||||
[key in string]: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type RelayerError = {
|
||||
@ -57,7 +55,7 @@ export interface RelayerStatus {
|
||||
fast: number;
|
||||
additionalProperties?: number;
|
||||
};
|
||||
netId: NetIdType;
|
||||
netId: number;
|
||||
ethPrices?: {
|
||||
[key in string]: string;
|
||||
};
|
||||
@ -107,14 +105,14 @@ export function parseSemanticVersion(version: string) {
|
||||
return groups as unknown as semanticVersion;
|
||||
}
|
||||
|
||||
export function isRelayerUpdated(relayerVersion: string, netId: NetIdType) {
|
||||
export function isRelayerUpdated(relayerVersion: string, netId: number | string) {
|
||||
const { major, patch, prerelease } = parseSemanticVersion(relayerVersion);
|
||||
// Save backwards compatibility with V4 relayers for Ethereum Mainnet
|
||||
const requiredMajor = netId === NetId.MAINNET ? '4' : '5';
|
||||
const requiredMajor = netId === 1 ? '4' : '5';
|
||||
const isUpdatedMajor = major === requiredMajor;
|
||||
|
||||
if (prerelease) return false;
|
||||
return isUpdatedMajor && (Number(patch) >= 5 || netId !== NetId.MAINNET); // Patch checking - also backwards compatibility for Mainnet
|
||||
return isUpdatedMajor && (Number(patch) >= 5 || Number(netId) !== 1); // Patch checking - also backwards compatibility for Mainnet
|
||||
}
|
||||
|
||||
export function calculateScore({ stakeBalance, tornadoServiceFee }: RelayerInfo, minFee = 0.33, maxFee = 0.53) {
|
||||
@ -141,28 +139,10 @@ export function getWeightRandom(weightsScores: bigint[], random: bigint) {
|
||||
return Math.floor(Math.random() * weightsScores.length);
|
||||
}
|
||||
|
||||
export type RelayerInstanceList = {
|
||||
[key in string]: {
|
||||
instanceAddress: {
|
||||
[key in string]: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export function getSupportedInstances(instanceList: RelayerInstanceList) {
|
||||
const rawList = Object.values(instanceList)
|
||||
.map(({ instanceAddress }) => {
|
||||
return Object.values(instanceAddress);
|
||||
})
|
||||
.flat();
|
||||
|
||||
return rawList.map((l) => getAddress(l));
|
||||
}
|
||||
|
||||
export function pickWeightedRandomRelayer(relayers: RelayerInfo[], netId: NetIdType) {
|
||||
export function pickWeightedRandomRelayer(relayers: RelayerInfo[], netId: string | number) {
|
||||
let minFee: number, maxFee: number;
|
||||
|
||||
if (netId !== NetId.MAINNET) {
|
||||
if (Number(netId) !== 1) {
|
||||
minFee = 0.01;
|
||||
maxFee = 0.3;
|
||||
}
|
||||
@ -179,7 +159,7 @@ export function pickWeightedRandomRelayer(relayers: RelayerInfo[], netId: NetIdT
|
||||
}
|
||||
|
||||
export interface RelayerClientConstructor {
|
||||
netId: NetIdType;
|
||||
netId: number | string;
|
||||
config: Config;
|
||||
Aggregator: Aggregator;
|
||||
fetchDataOptions?: fetchDataOptions;
|
||||
@ -190,14 +170,14 @@ export type RelayerClientWithdraw = snarkProofs & {
|
||||
};
|
||||
|
||||
export class RelayerClient {
|
||||
netId: NetIdType;
|
||||
netId: number;
|
||||
config: Config;
|
||||
Aggregator: Aggregator;
|
||||
selectedRelayer?: Relayer;
|
||||
fetchDataOptions?: fetchDataOptions;
|
||||
|
||||
constructor({ netId, config, Aggregator, fetchDataOptions }: RelayerClientConstructor) {
|
||||
this.netId = netId;
|
||||
this.netId = Number(netId);
|
||||
this.config = config;
|
||||
this.Aggregator = Aggregator;
|
||||
this.fetchDataOptions = fetchDataOptions;
|
||||
@ -240,7 +220,7 @@ export class RelayerClient {
|
||||
throw new Error('This relayer serves a different network');
|
||||
}
|
||||
|
||||
if (relayerAddress && this.netId === NetId.MAINNET && status.rewardAccount !== relayerAddress) {
|
||||
if (relayerAddress && this.netId === 1 && status.rewardAccount !== relayerAddress) {
|
||||
throw new Error('The Relayer reward address must match registered address');
|
||||
}
|
||||
|
||||
@ -283,9 +263,7 @@ export class RelayerClient {
|
||||
ensName,
|
||||
stakeBalance,
|
||||
relayerAddress,
|
||||
rewardAccount: getAddress(status.rewardAccount),
|
||||
instances: getSupportedInstances(status.instances),
|
||||
gasPrice: status.gasPrices?.fast,
|
||||
rewardAccount: status.rewardAccount,
|
||||
ethPrices: status.ethPrices,
|
||||
currentQueue: status.currentQueue,
|
||||
tornadoServiceFee: status.tornadoServiceFee,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Config, NetId, NetIdType } from '../networkConfig';
|
||||
import type { Config } from '../networkConfig';
|
||||
|
||||
export type statusInstanceType = {
|
||||
type: string;
|
||||
@ -110,7 +110,7 @@ const statusSchema: statusSchema = {
|
||||
required: ['rewardAccount', 'instances', 'netId', 'tornadoServiceFee', 'version', 'health'],
|
||||
};
|
||||
|
||||
export function getStatusSchema(netId: NetIdType, config: Config) {
|
||||
export function getStatusSchema(netId: number | string, config: Config) {
|
||||
const { tokens, optionalTokens = [], nativeCurrency } = config;
|
||||
|
||||
// deep copy schema
|
||||
@ -162,7 +162,7 @@ export function getStatusSchema(netId: NetIdType, config: Config) {
|
||||
|
||||
schema.properties.instances = instances;
|
||||
|
||||
if (netId === NetId.MAINNET) {
|
||||
if (Number(netId) === 1) {
|
||||
const _tokens = Object.keys(tokens).filter((t) => t !== nativeCurrency);
|
||||
|
||||
const ethPrices: statusEthPricesType = {
|
||||
|
@ -1,113 +0,0 @@
|
||||
/**
|
||||
* Create tree cache file from node.js
|
||||
*
|
||||
* Only works for node.js, modified from https://github.com/tornadocash/tornado-classic-ui/blob/master/scripts/updateTree.js
|
||||
*/
|
||||
import { MerkleTree } from '@tornado/fixed-merkle-tree';
|
||||
import BloomFilter from 'bloomfilter.js';
|
||||
import { saveUserFile } from './data';
|
||||
import { DepositsEvents } from './events';
|
||||
import type { NetIdType } from './networkConfig';
|
||||
|
||||
export interface TreeCacheConstructor {
|
||||
netId: NetIdType;
|
||||
amount: string;
|
||||
currency: string;
|
||||
userDirectory: string;
|
||||
PARTS_COUNT?: number;
|
||||
LEAVES?: number;
|
||||
zeroElement?: string;
|
||||
}
|
||||
|
||||
export interface treeMetadata {
|
||||
blockNumber: number;
|
||||
logIndex: number;
|
||||
transactionHash: string;
|
||||
timestamp: number;
|
||||
from: string;
|
||||
leafIndex: number;
|
||||
}
|
||||
|
||||
export class TreeCache {
|
||||
netId: NetIdType;
|
||||
amount: string;
|
||||
currency: string;
|
||||
userDirectory: string;
|
||||
|
||||
PARTS_COUNT: number;
|
||||
|
||||
constructor({ netId, amount, currency, userDirectory, PARTS_COUNT = 4 }: TreeCacheConstructor) {
|
||||
this.netId = netId;
|
||||
this.amount = amount;
|
||||
this.currency = currency;
|
||||
this.userDirectory = userDirectory;
|
||||
|
||||
this.PARTS_COUNT = PARTS_COUNT;
|
||||
}
|
||||
|
||||
getInstanceName(): string {
|
||||
return `deposits_${this.netId}_${this.currency}_${this.amount}`;
|
||||
}
|
||||
|
||||
async createTree(events: DepositsEvents[], tree: MerkleTree) {
|
||||
const bloom = new BloomFilter(events.length);
|
||||
|
||||
console.log(`Creating cached tree for ${this.getInstanceName()}\n`);
|
||||
|
||||
// events indexed by commitment
|
||||
const eventsData = events.reduce(
|
||||
(acc, { leafIndex, commitment, ...rest }, i) => {
|
||||
if (leafIndex !== i) {
|
||||
throw new Error(`leafIndex (${leafIndex}) !== i (${i})`);
|
||||
}
|
||||
|
||||
acc[commitment] = { ...rest, leafIndex };
|
||||
|
||||
return acc;
|
||||
},
|
||||
{} as { [key in string]: treeMetadata },
|
||||
);
|
||||
|
||||
const slices = tree.getTreeSlices(this.PARTS_COUNT);
|
||||
|
||||
await Promise.all(
|
||||
slices.map(async (slice, index) => {
|
||||
const metadata = slice.elements.reduce((acc, curr) => {
|
||||
if (index < this.PARTS_COUNT - 1) {
|
||||
bloom.add(curr);
|
||||
}
|
||||
acc.push(eventsData[curr]);
|
||||
return acc;
|
||||
}, [] as treeMetadata[]);
|
||||
|
||||
const dataString =
|
||||
JSON.stringify(
|
||||
{
|
||||
...slice,
|
||||
metadata,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
) + '\n';
|
||||
|
||||
const fileName = `${this.getInstanceName()}_slice${index + 1}.json`;
|
||||
|
||||
await saveUserFile({
|
||||
fileName,
|
||||
userDirectory: this.userDirectory,
|
||||
dataString,
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
const dataString = bloom.serialize() + '\n';
|
||||
|
||||
const fileName = `${this.getInstanceName()}_bloom.json`;
|
||||
|
||||
await saveUserFile({
|
||||
fileName,
|
||||
userDirectory: this.userDirectory,
|
||||
dataString,
|
||||
});
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { webcrypto } from 'crypto';
|
||||
import { URL } from 'url';
|
||||
import BN from 'bn.js';
|
||||
import type { BigNumberish } from 'ethers';
|
||||
|
||||
@ -16,8 +16,6 @@ export const isNode =
|
||||
}
|
||||
).browser && typeof globalThis.window === 'undefined';
|
||||
|
||||
export const crypto = isNode ? webcrypto : (globalThis.crypto as typeof webcrypto);
|
||||
|
||||
export const chunk = <T>(arr: T[], size: number): T[][] =>
|
||||
[...Array(Math.ceil(arr.length / size))].map((_, i) => arr.slice(size * i, size + size * i));
|
||||
|
||||
@ -37,28 +35,26 @@ export function validateUrl(url: string, protocols?: string[]) {
|
||||
}
|
||||
}
|
||||
|
||||
export function concatBytes(...arrays: Uint8Array[]): Uint8Array {
|
||||
const totalSize = arrays.reduce((acc, e) => acc + e.length, 0);
|
||||
const merged = new Uint8Array(totalSize);
|
||||
|
||||
arrays.forEach((array, i, arrays) => {
|
||||
const offset = arrays.slice(0, i).reduce((acc, e) => acc + e.length, 0);
|
||||
merged.set(array, offset);
|
||||
});
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
export function bufferToBytes(b: Buffer) {
|
||||
return new Uint8Array(b.buffer);
|
||||
}
|
||||
|
||||
export function bytesToBase64(bytes: Uint8Array) {
|
||||
return btoa(String.fromCharCode.apply(null, Array.from(bytes)));
|
||||
let binary = '';
|
||||
const len = bytes.byteLength;
|
||||
for (let i = 0; i < len; ++i) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
return btoa(binary);
|
||||
}
|
||||
|
||||
export function base64ToBytes(base64: string) {
|
||||
return Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
|
||||
const binaryString = atob(base64);
|
||||
const bytes = new Uint8Array(binaryString.length);
|
||||
for (let i = 0; i < binaryString.length; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
export function bytesToHex(bytes: Uint8Array) {
|
||||
@ -70,16 +66,6 @@ export function bytesToHex(bytes: Uint8Array) {
|
||||
);
|
||||
}
|
||||
|
||||
export function hexToBytes(hexString: string) {
|
||||
if (hexString.slice(0, 2) === '0x') {
|
||||
hexString = hexString.replace('0x', '');
|
||||
}
|
||||
if (hexString.length % 2 !== 0) {
|
||||
hexString = '0' + hexString;
|
||||
}
|
||||
return Uint8Array.from((hexString.match(/.{1,2}/g) as string[]).map((byte) => parseInt(byte, 16)));
|
||||
}
|
||||
|
||||
// Convert BE encoded bytes (Buffer | Uint8Array) array to BigInt
|
||||
export function bytesToBN(bytes: Uint8Array) {
|
||||
return BigInt(bytesToHex(bytes));
|
||||
|
25
src/types/bloomfilter.js.d.ts
vendored
25
src/types/bloomfilter.js.d.ts
vendored
@ -1,25 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
declare module 'bloomfilter.js' {
|
||||
export default class BloomFilter {
|
||||
m: number;
|
||||
k: number;
|
||||
size: number;
|
||||
bitview: any;
|
||||
|
||||
constructor(n: number, false_postive_tolerance?: number);
|
||||
|
||||
calculateHash(x: number, m: number, i: number): number;
|
||||
|
||||
test(data: any): boolean;
|
||||
|
||||
add(data: any): void;
|
||||
|
||||
bytelength(): number;
|
||||
|
||||
view(): Uint8Array;
|
||||
|
||||
serialize(): string;
|
||||
|
||||
deserialize(serialized: string): BloomFilter;
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2
static/merkleTreeWorker.js
vendored
2
static/merkleTreeWorker.js
vendored
@ -19824,5 +19824,5 @@ if (isNode && threads) {
|
||||
postMessage(merkleTree.toString());
|
||||
}));
|
||||
} else {
|
||||
throw new Error("This browser / environment does not support workers!");
|
||||
throw new Error("This browser / environment doesn't support workers!");
|
||||
}
|
||||
|
200416
static/merkleTreeWorker.umd.js
vendored
200416
static/merkleTreeWorker.umd.js
vendored
File diff suppressed because one or more lines are too long
@ -2,7 +2,6 @@
|
||||
"compilerOptions": {
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
"./src/types",
|
||||
],
|
||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||
|
||||
|
@ -1,100 +0,0 @@
|
||||
const esbuild = require('esbuild');
|
||||
const path = require('path');
|
||||
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
|
||||
|
||||
const esbuildLoader = {
|
||||
test: /\.ts?$/,
|
||||
loader: 'esbuild-loader',
|
||||
options: {
|
||||
loader: 'ts',
|
||||
target: 'es2016',
|
||||
implementation: esbuild
|
||||
}
|
||||
}
|
||||
|
||||
const commonAlias = {
|
||||
fs: false,
|
||||
'fs/promises': false,
|
||||
'path': false,
|
||||
'url': false,
|
||||
'worker_threads': false,
|
||||
'fflate': 'fflate/browser',
|
||||
'@colors/colors': false,
|
||||
'cli-table3': false,
|
||||
'commander': false,
|
||||
'http-proxy-agent': false,
|
||||
'https-proxy-agent': false,
|
||||
'socks-proxy-agent': false,
|
||||
}
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
mode: 'production',
|
||||
module: {
|
||||
rules: [esbuildLoader]
|
||||
},
|
||||
entry: './src/index.ts',
|
||||
output: {
|
||||
filename: 'index.umd.js',
|
||||
path: path.resolve(__dirname, './dist'),
|
||||
library: 'Tornado',
|
||||
libraryTarget: 'umd'
|
||||
},
|
||||
plugins: [
|
||||
new NodePolyfillPlugin(),
|
||||
],
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js'],
|
||||
alias: {
|
||||
...commonAlias,
|
||||
}
|
||||
},
|
||||
optimization: {
|
||||
minimize: false,
|
||||
}
|
||||
},
|
||||
{
|
||||
mode: 'production',
|
||||
module: {
|
||||
rules: [esbuildLoader]
|
||||
},
|
||||
entry: './src/cli.ts',
|
||||
output: {
|
||||
filename: 'cli.js',
|
||||
path: path.resolve(__dirname, './dist'),
|
||||
},
|
||||
target: 'node',
|
||||
plugins: [],
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js'],
|
||||
alias: {}
|
||||
},
|
||||
optimization: {
|
||||
minimize: false,
|
||||
}
|
||||
},
|
||||
{
|
||||
mode: 'production',
|
||||
module: {
|
||||
rules: [esbuildLoader]
|
||||
},
|
||||
entry: './src/merkleTreeWorker.ts',
|
||||
output: {
|
||||
filename: 'merkleTreeWorker.umd.js',
|
||||
path: path.resolve(__dirname, './static'),
|
||||
libraryTarget: 'umd'
|
||||
},
|
||||
plugins: [
|
||||
new NodePolyfillPlugin(),
|
||||
],
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js'],
|
||||
alias: {
|
||||
...commonAlias,
|
||||
}
|
||||
},
|
||||
optimization: {
|
||||
minimize: false,
|
||||
}
|
||||
}
|
||||
];
|
Loading…
x
Reference in New Issue
Block a user