Compare commits

..

No commits in common. "722c426fcb729fc554c3daed21842fcf8fb3c76e" and "68fcf07c2a344a1f7f74895301f362aa059b53e2" have entirely different histories.

39 changed files with 37075 additions and 63489 deletions

View File

@ -1,25 +0,0 @@
# Dockefile from https://notes.ethereum.org/@GW1ZUbNKR5iRjjKYx6_dJQ/Bk8zsJ9xj
# FROM node:20.18.0-bullseye-slim
FROM node@sha256:9b558df8f10198fcd1f48cf344c55c4442c3446b8a9a69487523b3d890a4a59e
# install wget, git and necessary certificates
RUN apt update && apt install --yes --no-install-recommends wget git apt-transport-https ca-certificates && rm -rf /var/lib/apt/lists/*
ENV GIT_REPOSITORY=https://git.tornado.ws/tornadocontrib/tornado-core.git
# From development branch, double check with tornado.ws
ENV GIT_COMMIT_HASH=f16bb2ed12464dce4f31aa5a237bb1643989e02d
# clone the repository
RUN mkdir /app/
WORKDIR /app
# Simple hack to fetch only commit and nothing more (no need to download 1GB sized repo, only 100MB would be enough)
RUN git init && \
git remote add origin $GIT_REPOSITORY && \
git fetch --depth 1 origin $GIT_COMMIT_HASH && \
git checkout $GIT_COMMIT_HASH
# install, build and prep for deployment
RUN yarn install --frozen-lockfile --ignore-scripts
RUN yarn build

View File

@ -4,8 +4,6 @@
# Tornado Core (@tornado/core) # Tornado Core (@tornado/core)
### Notice: Repository migrated to [tornado-scripts](https://github.com/tornadocontrib/tornado-scripts) to avoid naming conflict with legacy tornado-core repository
🛠 An SDK for building applications on top of [Privacy Pools](https://www.forbes.com/sites/tomerniv/2023/09/07/privacy-pools-bridging-the-gap-between-blockchain-and-regulatory-compliance) 🛠 An SDK for building applications on top of [Privacy Pools](https://www.forbes.com/sites/tomerniv/2023/09/07/privacy-pools-bridging-the-gap-between-blockchain-and-regulatory-compliance)
[![Telegram Badge](https://img.shields.io/badge/Join%20Group-telegram?style=flat&logo=telegram&color=blue&link=https%3A%2F%2Ft.me%2Ftornadoofficial)](https://t.me/tornadoofficial) [![Element Badge](https://img.shields.io/badge/Join%20Element%20Chat-Element?style=flat&logo=element&color=green&link=https%3A%2F%2Felement.tornadocash.social%2F)](https://element.tornadocash.social) [![Discourse Badge](https://img.shields.io/badge/Discourse-Discourse?style=flat&logo=Discourse&color=black&link=https%3A%2F%2Fforum.tornado.ws%2F)](https://forum.tornado.ws/) [![Telegram Badge](https://img.shields.io/badge/Join%20Group-telegram?style=flat&logo=telegram&color=blue&link=https%3A%2F%2Ft.me%2Ftornadoofficial)](https://t.me/tornadoofficial) [![Element Badge](https://img.shields.io/badge/Join%20Element%20Chat-Element?style=flat&logo=element&color=green&link=https%3A%2F%2Felement.tornadocash.social%2F)](https://element.tornadocash.social) [![Discourse Badge](https://img.shields.io/badge/Discourse-Discourse?style=flat&logo=Discourse&color=black&link=https%3A%2F%2Fforum.tornado.ws%2F)](https://forum.tornado.ws/)

16
dist/events/base.d.ts vendored
View File

@ -1,15 +1,15 @@
import { BaseContract, Provider, EventLog } from 'ethers'; import { BaseContract, Provider, EventLog } from 'ethers';
import { Tornado, TornadoRouter, TornadoProxyLight, Governance, RelayerRegistry, Echoer, Aggregator } from '@tornado/contracts'; import { Tornado, TornadoRouter, TornadoProxyLight, Governance, RelayerRegistry, Echoer, Aggregator } from '@tornado/contracts';
import type { MerkleTree } from 'fixed-merkle-tree'; import type { MerkleTree } from '@tornado/fixed-merkle-tree';
import { BatchEventsService, BatchBlockService, BatchTransactionService, BatchEventOnProgress, BatchBlockOnProgress } from '../batch'; import { BatchEventsService, BatchBlockService, BatchTransactionService, BatchEventOnProgress, BatchBlockOnProgress } from '../batch';
import { fetchDataOptions } from '../providers'; import { fetchDataOptions } from '../providers';
import { type NetIdType, type SubdomainMap } from '../networkConfig'; import { type NetIdType, type SubdomainMap } from '../networkConfig';
import { RelayerParams } from '../relayerClient'; import { RelayerParams } from '../relayerClient';
import type { TovarishClient } from '../tovarishClient'; import type { TovarishClient } from '../tovarishClient';
import type { ERC20, ReverseRecords } from '../typechain'; import type { ReverseRecords } from '../typechain';
import type { MerkleTreeService } from '../merkleTree'; import type { MerkleTreeService } from '../merkleTree';
import type { DepositType } from '../deposits'; import type { DepositType } from '../deposits';
import type { BaseEvents, CachedEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, AllGovernanceEvents, GovernanceProposalCreatedEvents, GovernanceVotedEvents, EchoEvents, AllRelayerRegistryEvents, StakeBurnedEvents, MultiDepositsEvents, MultiWithdrawalsEvents, TransferEvents } from './types'; import type { BaseEvents, CachedEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, AllGovernanceEvents, GovernanceProposalCreatedEvents, GovernanceVotedEvents, EchoEvents, AllRelayerRegistryEvents, StakeBurnedEvents, MultiDepositsEvents, MultiWithdrawalsEvents } from './types';
export interface BaseEventsServiceConstructor { export interface BaseEventsServiceConstructor {
netId: NetIdType; netId: NetIdType;
provider: Provider; provider: Provider;
@ -44,9 +44,6 @@ export declare class BaseEventsService<EventType extends MinimalEvents> {
* Events from remote cache (Either from local cache, CDN, or from IPFS) * Events from remote cache (Either from local cache, CDN, or from IPFS)
*/ */
getEventsFromCache(): Promise<CachedEvents<EventType>>; getEventsFromCache(): Promise<CachedEvents<EventType>>;
/**
* This may not return in sorted events when called from browser, make sure to sort it again when directly called
*/
getSavedEvents(): Promise<BaseEvents<EventType> | CachedEvents<EventType>>; getSavedEvents(): Promise<BaseEvents<EventType> | CachedEvents<EventType>>;
getEventsFromRpc({ fromBlock, toBlock, }: { getEventsFromRpc({ fromBlock, toBlock, }: {
fromBlock: number; fromBlock: number;
@ -255,10 +252,3 @@ export declare class BaseRevenueService extends BaseEventsService<StakeBurnedEve
getTovarishType(): string; getTovarishType(): string;
formatEvents(events: EventLog[]): Promise<StakeBurnedEvents[]>; formatEvents(events: EventLog[]): Promise<StakeBurnedEvents[]>;
} }
export interface BaseTransferServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
Token: ERC20;
}
export declare class BaseTransferService extends BaseEventsService<TransferEvents> {
constructor(serviceConstructor: BaseTransferServiceConstructor);
formatEvents(events: EventLog[]): Promise<TransferEvents[]>;
}

47
dist/events/db.d.ts vendored
View File

@ -1,10 +1,10 @@
import { IndexedDB } from '../idb'; import { IndexedDB } from '../idb';
import { BaseTornadoService, BaseTornadoServiceConstructor, BaseEchoService, BaseEchoServiceConstructor, BaseEncryptedNotesService, BaseEncryptedNotesServiceConstructor, BaseGovernanceService, BaseGovernanceServiceConstructor, BaseRegistryService, BaseRegistryServiceConstructor, BaseRevenueService, BaseRevenueServiceConstructor, CachedRelayers, BaseMultiTornadoService, BaseMultiTornadoServiceConstructor } from './base'; import { BaseTornadoService, BaseTornadoServiceConstructor, BaseEchoService, BaseEchoServiceConstructor, BaseEncryptedNotesService, BaseEncryptedNotesServiceConstructor, BaseGovernanceService, BaseGovernanceServiceConstructor, BaseRegistryService, BaseRegistryServiceConstructor, BaseRevenueService, BaseRevenueServiceConstructor, CachedRelayers } from './base';
import { BaseEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, CachedEvents, EchoEvents, EncryptedNotesEvents, AllGovernanceEvents, AllRelayerRegistryEvents, StakeBurnedEvents, MultiDepositsEvents, MultiWithdrawalsEvents } from './types'; import { BaseEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, CachedEvents, EchoEvents, EncryptedNotesEvents, AllGovernanceEvents, AllRelayerRegistryEvents, StakeBurnedEvents } from './types';
export declare function saveDBEvents<T extends MinimalEvents>({ idb, instanceName, newEvents, lastBlock, }: { export declare function saveDBEvents<T extends MinimalEvents>({ idb, instanceName, events, lastBlock, }: {
idb: IndexedDB; idb: IndexedDB;
instanceName: string; instanceName: string;
newEvents: T[]; events: T[];
lastBlock: number; lastBlock: number;
}): Promise<void>; }): Promise<void>;
export declare function loadDBEvents<T extends MinimalEvents>({ idb, instanceName, }: { export declare function loadDBEvents<T extends MinimalEvents>({ idb, instanceName, }: {
@ -28,24 +28,7 @@ export declare class DBTornadoService extends BaseTornadoService {
constructor(params: DBTornadoServiceConstructor); constructor(params: DBTornadoServiceConstructor);
getEventsFromDB(): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>>; getEventsFromDB(): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>>;
getEventsFromCache(): Promise<CachedEvents<DepositsEvents | WithdrawalsEvents>>; getEventsFromCache(): Promise<CachedEvents<DepositsEvents | WithdrawalsEvents>>;
saveEvents({ newEvents, lastBlock, }: BaseEvents<DepositsEvents | WithdrawalsEvents> & { saveEvents({ events, lastBlock }: BaseEvents<DepositsEvents | WithdrawalsEvents>): Promise<void>;
newEvents: (DepositsEvents | WithdrawalsEvents)[];
}): Promise<void>;
}
export interface DBMultiTornadoServiceConstructor extends BaseMultiTornadoServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export declare class DBMultiTornadoService extends BaseMultiTornadoService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
constructor(params: DBMultiTornadoServiceConstructor);
getEventsFromDB(): Promise<BaseEvents<MultiDepositsEvents | MultiWithdrawalsEvents>>;
getEventsFromCache(): Promise<CachedEvents<MultiDepositsEvents | MultiWithdrawalsEvents>>;
saveEvents({ newEvents, lastBlock, }: BaseEvents<MultiDepositsEvents | MultiWithdrawalsEvents> & {
newEvents: (MultiDepositsEvents | MultiWithdrawalsEvents)[];
}): Promise<void>;
} }
export interface DBEchoServiceConstructor extends BaseEchoServiceConstructor { export interface DBEchoServiceConstructor extends BaseEchoServiceConstructor {
staticUrl: string; staticUrl: string;
@ -58,9 +41,7 @@ export declare class DBEchoService extends BaseEchoService {
constructor(params: DBEchoServiceConstructor); constructor(params: DBEchoServiceConstructor);
getEventsFromDB(): Promise<BaseEvents<EchoEvents>>; getEventsFromDB(): Promise<BaseEvents<EchoEvents>>;
getEventsFromCache(): Promise<CachedEvents<EchoEvents>>; getEventsFromCache(): Promise<CachedEvents<EchoEvents>>;
saveEvents({ newEvents, lastBlock }: BaseEvents<EchoEvents> & { saveEvents({ events, lastBlock }: BaseEvents<EchoEvents>): Promise<void>;
newEvents: EchoEvents[];
}): Promise<void>;
} }
export interface DBEncryptedNotesServiceConstructor extends BaseEncryptedNotesServiceConstructor { export interface DBEncryptedNotesServiceConstructor extends BaseEncryptedNotesServiceConstructor {
staticUrl: string; staticUrl: string;
@ -73,9 +54,7 @@ export declare class DBEncryptedNotesService extends BaseEncryptedNotesService {
constructor(params: DBEncryptedNotesServiceConstructor); constructor(params: DBEncryptedNotesServiceConstructor);
getEventsFromDB(): Promise<BaseEvents<EncryptedNotesEvents>>; getEventsFromDB(): Promise<BaseEvents<EncryptedNotesEvents>>;
getEventsFromCache(): Promise<CachedEvents<EncryptedNotesEvents>>; getEventsFromCache(): Promise<CachedEvents<EncryptedNotesEvents>>;
saveEvents({ newEvents, lastBlock, }: BaseEvents<EncryptedNotesEvents> & { saveEvents({ events, lastBlock }: BaseEvents<EncryptedNotesEvents>): Promise<void>;
newEvents: EncryptedNotesEvents[];
}): Promise<void>;
} }
export interface DBGovernanceServiceConstructor extends BaseGovernanceServiceConstructor { export interface DBGovernanceServiceConstructor extends BaseGovernanceServiceConstructor {
staticUrl: string; staticUrl: string;
@ -88,9 +67,7 @@ export declare class DBGovernanceService extends BaseGovernanceService {
constructor(params: DBGovernanceServiceConstructor); constructor(params: DBGovernanceServiceConstructor);
getEventsFromDB(): Promise<BaseEvents<AllGovernanceEvents>>; getEventsFromDB(): Promise<BaseEvents<AllGovernanceEvents>>;
getEventsFromCache(): Promise<CachedEvents<AllGovernanceEvents>>; getEventsFromCache(): Promise<CachedEvents<AllGovernanceEvents>>;
saveEvents({ newEvents, lastBlock }: BaseEvents<AllGovernanceEvents> & { saveEvents({ events, lastBlock }: BaseEvents<AllGovernanceEvents>): Promise<void>;
newEvents: AllGovernanceEvents[];
}): Promise<void>;
} }
export interface DBRegistryServiceConstructor extends BaseRegistryServiceConstructor { export interface DBRegistryServiceConstructor extends BaseRegistryServiceConstructor {
staticUrl: string; staticUrl: string;
@ -104,9 +81,7 @@ export declare class DBRegistryService extends BaseRegistryService {
constructor(params: DBRegistryServiceConstructor); constructor(params: DBRegistryServiceConstructor);
getEventsFromDB(): Promise<BaseEvents<AllRelayerRegistryEvents>>; getEventsFromDB(): Promise<BaseEvents<AllRelayerRegistryEvents>>;
getEventsFromCache(): Promise<CachedEvents<AllRelayerRegistryEvents>>; getEventsFromCache(): Promise<CachedEvents<AllRelayerRegistryEvents>>;
saveEvents({ newEvents, lastBlock, }: BaseEvents<AllRelayerRegistryEvents> & { saveEvents({ events, lastBlock }: BaseEvents<AllRelayerRegistryEvents>): Promise<void>;
newEvents: AllRelayerRegistryEvents[];
}): Promise<void>;
getRelayersFromDB(): Promise<CachedRelayers>; getRelayersFromDB(): Promise<CachedRelayers>;
getRelayersFromCache(): Promise<CachedRelayers>; getRelayersFromCache(): Promise<CachedRelayers>;
saveRelayers(cachedRelayers: CachedRelayers): Promise<void>; saveRelayers(cachedRelayers: CachedRelayers): Promise<void>;
@ -123,7 +98,5 @@ export declare class DBRevenueService extends BaseRevenueService {
constructor(params: DBRevenueServiceConstructor); constructor(params: DBRevenueServiceConstructor);
getEventsFromDB(): Promise<BaseEvents<StakeBurnedEvents>>; getEventsFromDB(): Promise<BaseEvents<StakeBurnedEvents>>;
getEventsFromCache(): Promise<CachedEvents<StakeBurnedEvents>>; getEventsFromCache(): Promise<CachedEvents<StakeBurnedEvents>>;
saveEvents({ newEvents, lastBlock }: BaseEvents<StakeBurnedEvents> & { saveEvents({ events, lastBlock }: BaseEvents<StakeBurnedEvents>): Promise<void>;
newEvents: StakeBurnedEvents[];
}): Promise<void>;
} }

View File

@ -99,8 +99,3 @@ export interface EchoEvents extends MinimalEvents {
export interface EncryptedNotesEvents extends MinimalEvents { export interface EncryptedNotesEvents extends MinimalEvents {
encryptedNote: string; encryptedNote: string;
} }
export interface TransferEvents extends MinimalEvents {
from: string;
to: string;
value: bigint;
}

2
dist/fees.d.ts vendored
View File

@ -29,7 +29,7 @@ export declare class TornadoFeeOracle {
* (A single block can bump 12.5% of fees, see the methodology https://hackmd.io/@tvanepps/1559-wallets) * (A single block can bump 12.5% of fees, see the methodology https://hackmd.io/@tvanepps/1559-wallets)
* (Still it is recommended to use 100% premium for sending transactions to prevent stucking it) * (Still it is recommended to use 100% premium for sending transactions to prevent stucking it)
*/ */
gasPrice(premium?: number): Promise<bigint>; gasPrice(): Promise<bigint>;
/** /**
* Calculate L1 fee for op-stack chains * Calculate L1 fee for op-stack chains
* *

11
dist/hashes.json vendored
View File

@ -1,11 +0,0 @@
{
"dist/index.js": "sha384-txpjgDLxNbeXsLgVCyNAwpaJRS0SmFN/ITfadSo8+xzSvLqwa5bQ9GoxQ1Su8QEr",
"dist/index.mjs": "sha384-CrEHmX4zKIv/68CKWElNzvKk6FWRMMkKV8JmqL1KqYCxO73LPEAjDqxTYpxUuDBy",
"dist/merkleTreeWorker.js": "sha384-XVv9HRGDZlaF0LeEZNQygle31UY6yvIwsZ4GWCTZUX7O/hZ7N5Zwpi3GqnHSBYzW",
"dist/merkleTreeWorker.umd.js": "sha384-e5B65ZZ4IxKVOU1o02K6IL2tjJof20QCcEtD+vKe1cPmyfW2BPCHWDPIbPksIpvJ",
"dist/merkleTreeWorker.umd.min.js": "sha384-AxQv1da+lSi3gMYkdGQuR1WN1+4HB8IT3cPFa17HBj14+ZzdZN6SS1fCw5Izc2rr",
"dist/tornado.umd.js": "sha384-xTUkkUTm3aBsnHCUnVGxRgieAu3z4wCwrKT1DFj8VyCk/eZZO9nq+yP4/McLRfB4",
"dist/tornado.umd.min.js": "sha384-ubqr6m6jEOPf7LQz0pXKmEo7tCCbNUAE+iSZWK6X/f7i4wt14rYW7pUcSzw5glth",
"dist/tornadoContracts.umd.js": "sha384-bFq/cemb0bP0JbIq8p75n0UR8smQ/2Yh69pjegzSuu0upawO3sKOjehY8SjX85Xh",
"dist/tornadoContracts.umd.min.js": "sha384-4ay7cmK0auAgZH1xfAsqyN6GtnHBNNgh9C22qy0rHxKicDzNtTsnNZDbz0qmd9GI"
}

525
dist/index.js vendored
View File

@ -12,9 +12,9 @@ var circomlibjs = require('circomlibjs');
var ethSigUtil = require('@metamask/eth-sig-util'); var ethSigUtil = require('@metamask/eth-sig-util');
var idb = require('idb'); var idb = require('idb');
var worker_threads = require('worker_threads'); var worker_threads = require('worker_threads');
var fixedMerkleTree = require('fixed-merkle-tree'); var fixedMerkleTree = require('@tornado/fixed-merkle-tree');
var websnarkUtils = require('websnark/src/utils'); var websnarkUtils = require('@tornado/websnark/src/utils');
var websnarkGroth = require('websnark/src/groth16'); var websnarkGroth = require('@tornado/websnark/src/groth16');
function _interopNamespaceDefault(e) { function _interopNamespaceDefault(e) {
var n = Object.create(null); var n = Object.create(null);
@ -699,7 +699,7 @@ function getProviderWithNetId(netId, rpcUrl, config, fetchOptions) {
return provider; return provider;
} }
const populateTransaction = async (signer, tx) => { const populateTransaction = async (signer, tx) => {
const provider = signer.readonlyProvider || signer.provider; const provider = signer.provider;
if (!tx.from) { if (!tx.from) {
tx.from = signer.address; tx.from = signer.address;
} else if (tx.from !== signer.address) { } else if (tx.from !== signer.address) {
@ -794,14 +794,12 @@ class TornadoRpcSigner extends ethers.JsonRpcSigner {
gasLimitBump; gasLimitBump;
gasFailover; gasFailover;
bumpNonce; bumpNonce;
readonlyProvider; constructor(provider, address, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce } = {}) {
constructor(provider, address, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce, readonlyProvider } = {}) {
super(provider, address); super(provider, address);
this.gasPriceBump = gasPriceBump ?? 0; this.gasPriceBump = gasPriceBump ?? 0;
this.gasLimitBump = gasLimitBump ?? 3e3; this.gasLimitBump = gasLimitBump ?? 3e3;
this.gasFailover = gasFailover ?? false; this.gasFailover = gasFailover ?? false;
this.bumpNonce = bumpNonce ?? false; this.bumpNonce = bumpNonce ?? false;
this.readonlyProvider = readonlyProvider;
} }
async sendUncheckedTransaction(tx) { async sendUncheckedTransaction(tx) {
return super.sendUncheckedTransaction(await populateTransaction(this, tx)); return super.sendUncheckedTransaction(await populateTransaction(this, tx));
@ -837,8 +835,6 @@ var NetId = /* @__PURE__ */ ((NetId2) => {
NetId2[NetId2["POLYGON"] = 137] = "POLYGON"; NetId2[NetId2["POLYGON"] = 137] = "POLYGON";
NetId2[NetId2["OPTIMISM"] = 10] = "OPTIMISM"; NetId2[NetId2["OPTIMISM"] = 10] = "OPTIMISM";
NetId2[NetId2["ARBITRUM"] = 42161] = "ARBITRUM"; NetId2[NetId2["ARBITRUM"] = 42161] = "ARBITRUM";
NetId2[NetId2["BASE"] = 8453] = "BASE";
NetId2[NetId2["BLAST"] = 81457] = "BLAST";
NetId2[NetId2["GNOSIS"] = 100] = "GNOSIS"; NetId2[NetId2["GNOSIS"] = 100] = "GNOSIS";
NetId2[NetId2["AVALANCHE"] = 43114] = "AVALANCHE"; NetId2[NetId2["AVALANCHE"] = 43114] = "AVALANCHE";
NetId2[NetId2["SEPOLIA"] = 11155111] = "SEPOLIA"; NetId2[NetId2["SEPOLIA"] = 11155111] = "SEPOLIA";
@ -865,10 +861,6 @@ const defaultConfig = {
name: "MEV Blocker", name: "MEV Blocker",
url: "https://rpc.mevblocker.io" url: "https://rpc.mevblocker.io"
}, },
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com"
},
keydonix: { keydonix: {
name: "Horswap ( Keydonix )", name: "Horswap ( Keydonix )",
url: "https://ethereum.keydonix.com/v1/mainnet" url: "https://ethereum.keydonix.com/v1/mainnet"
@ -988,10 +980,10 @@ const defaultConfig = {
[56 /* BSC */]: { [56 /* BSC */]: {
rpcCallRetryAttempt: 15, rpcCallRetryAttempt: 15,
gasPrices: { gasPrices: {
instant: 3, instant: 5,
fast: 1, fast: 5,
standard: 1, standard: 5,
low: 1 low: 5
}, },
nativeCurrency: "bnb", nativeCurrency: "bnb",
currencyName: "BNB", currencyName: "BNB",
@ -1016,10 +1008,6 @@ const defaultConfig = {
name: "BNB Chain 2", name: "BNB Chain 2",
url: "https://bsc-dataseed1.ninicoin.io" url: "https://bsc-dataseed1.ninicoin.io"
}, },
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/bsc"
},
nodereal: { nodereal: {
name: "NodeReal", name: "NodeReal",
url: "https://binance.nodereal.io" url: "https://binance.nodereal.io"
@ -1043,39 +1031,10 @@ const defaultConfig = {
}, },
symbol: "BNB", symbol: "BNB",
decimals: 18 decimals: 18
},
usdt: {
instanceAddress: {
"10": "0x261fB4f84bb0BdEe7E035B6a8a08e5c35AdacdDD",
"100": "0x3957861d4897d883C9b944C0b4E22bBd0DDE6e21",
"1000": "0x6D180403AdFb39F70983eB51A033C5e52eb9BB69",
"10000": "0x3722662D8AaB07B216B14C02eF0ee940d14A4200"
},
instanceApproval: true,
tokenAddress: "0x55d398326f99059fF775485246999027B3197955",
tokenGasLimit: 7e4,
symbol: "USDT",
decimals: 18,
gasLimit: 7e5
},
btcb: {
instanceAddress: {
"0.0001": "0x736dABbFc8101Ae75287104eCcf67e45D7369Ae1",
"0.001": "0x82c7Ce6f1F158cEC5536d591a2BC19864b3CA823",
"0.01": "0x8284c96679037d8081E498d8F767cA5a140BFAAf",
"0.1": "0x2bcD128Ce23ee30Ee945E613ff129c4DE1102C79"
},
instanceApproval: true,
tokenAddress: "0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c",
tokenGasLimit: 7e4,
symbol: "BTCB",
decimals: 18,
gasLimit: 7e5
} }
}, },
optionalTokens: ["usdt", "btcb"],
relayerEnsSubdomain: "bsc-tornado", relayerEnsSubdomain: "bsc-tornado",
pollInterval: 3, pollInterval: 10,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 8159269, NOTE_ACCOUNT_BLOCK: 8159269,
ENCRYPTED_NOTES_BLOCK: 8159269 ENCRYPTED_NOTES_BLOCK: 8159269
@ -1084,9 +1043,9 @@ const defaultConfig = {
[137 /* POLYGON */]: { [137 /* POLYGON */]: {
rpcCallRetryAttempt: 15, rpcCallRetryAttempt: 15,
gasPrices: { gasPrices: {
instant: 60, instant: 100,
fast: 30, fast: 75,
standard: 30, standard: 50,
low: 30 low: 30
}, },
nativeCurrency: "matic", nativeCurrency: "matic",
@ -1126,7 +1085,7 @@ const defaultConfig = {
} }
}, },
relayerEnsSubdomain: "polygon-tornado", relayerEnsSubdomain: "polygon-tornado",
pollInterval: 2, pollInterval: 10,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 16257996, NOTE_ACCOUNT_BLOCK: 16257996,
ENCRYPTED_NOTES_BLOCK: 16257996 ENCRYPTED_NOTES_BLOCK: 16257996
@ -1168,20 +1127,17 @@ const defaultConfig = {
tokens: { tokens: {
eth: { eth: {
instanceAddress: { instanceAddress: {
"0.001": "0x82859DC3697062c16422E9b5e8Ba1B6a6EC72c76",
"0.01": "0xA287c40411685438750a247Ca67488DEBe56EE32",
"0.1": "0x84443CFd09A48AF6eF360C6976C5392aC5023a1F", "0.1": "0x84443CFd09A48AF6eF360C6976C5392aC5023a1F",
"1": "0xd47438C816c9E7f2E2888E060936a499Af9582b3", "1": "0xd47438C816c9E7f2E2888E060936a499Af9582b3",
"10": "0x330bdFADE01eE9bF63C209Ee33102DD334618e0a", "10": "0x330bdFADE01eE9bF63C209Ee33102DD334618e0a",
"100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD" "100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD"
}, },
optionalInstances: ["0.001", "0.01"],
symbol: "ETH", symbol: "ETH",
decimals: 18 decimals: 18
} }
}, },
relayerEnsSubdomain: "optimism-tornado", relayerEnsSubdomain: "optimism-tornado",
pollInterval: 2, pollInterval: 15,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 2243694, NOTE_ACCOUNT_BLOCK: 2243694,
ENCRYPTED_NOTES_BLOCK: 2243694 ENCRYPTED_NOTES_BLOCK: 2243694
@ -1190,10 +1146,10 @@ const defaultConfig = {
[42161 /* ARBITRUM */]: { [42161 /* ARBITRUM */]: {
rpcCallRetryAttempt: 15, rpcCallRetryAttempt: 15,
gasPrices: { gasPrices: {
instant: 0.02, instant: 4,
fast: 0.02, fast: 3,
standard: 0.02, standard: 2.52,
low: 0.02 low: 2.29
}, },
nativeCurrency: "eth", nativeCurrency: "eth",
currencyName: "ETH", currencyName: "ETH",
@ -1214,10 +1170,6 @@ const defaultConfig = {
name: "Arbitrum", name: "Arbitrum",
url: "https://arb1.arbitrum.io/rpc" url: "https://arb1.arbitrum.io/rpc"
}, },
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/arbitrum"
},
stackup: { stackup: {
name: "Stackup", name: "Stackup",
url: "https://public.stackup.sh/api/v1/node/arbitrum-one" url: "https://public.stackup.sh/api/v1/node/arbitrum-one"
@ -1230,166 +1182,22 @@ const defaultConfig = {
tokens: { tokens: {
eth: { eth: {
instanceAddress: { instanceAddress: {
"0.001": "0x82859DC3697062c16422E9b5e8Ba1B6a6EC72c76",
"0.01": "0xA287c40411685438750a247Ca67488DEBe56EE32",
"0.1": "0x84443CFd09A48AF6eF360C6976C5392aC5023a1F", "0.1": "0x84443CFd09A48AF6eF360C6976C5392aC5023a1F",
"1": "0xd47438C816c9E7f2E2888E060936a499Af9582b3", "1": "0xd47438C816c9E7f2E2888E060936a499Af9582b3",
"10": "0x330bdFADE01eE9bF63C209Ee33102DD334618e0a", "10": "0x330bdFADE01eE9bF63C209Ee33102DD334618e0a",
"100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD" "100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD"
}, },
optionalInstances: ["0.001", "0.01"],
symbol: "ETH", symbol: "ETH",
decimals: 18 decimals: 18
} }
}, },
relayerEnsSubdomain: "arbitrum-tornado", relayerEnsSubdomain: "arbitrum-tornado",
pollInterval: 2, pollInterval: 15,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 3430605, NOTE_ACCOUNT_BLOCK: 3430605,
ENCRYPTED_NOTES_BLOCK: 3430605 ENCRYPTED_NOTES_BLOCK: 3430605
} }
}, },
[8453 /* BASE */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 0.1,
fast: 0.06,
standard: 0.05,
low: 0.02
},
nativeCurrency: "eth",
currencyName: "ETH",
explorerUrl: "https://basescan.org",
merkleTreeHeight: 20,
emptyElement: "21663839004416932945382355908790599225266501822907911457504978515578255421292",
networkName: "Base",
deployedBlock: 23149794,
stablecoin: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
multicallContract: "0xcA11bde05977b3631167028862bE2a173976CA11",
routerContract: "0x0D5550d52428E7e3175bfc9550207e4ad3859b17",
echoContract: "0xa75BF2815618872f155b7C4B0C81bF990f5245E4",
offchainOracleContract: "0x00000000000D6FFc74A8feb35aF5827bf57f6786",
ovmGasPriceOracleContract: "0x420000000000000000000000000000000000000F",
tornadoSubgraph: "tornadocash/base-tornado-subgraph",
subgraphs: {},
rpcUrls: {
Base: {
name: "Base",
url: "https://mainnet.base.org"
},
stackup: {
name: "Stackup",
url: "https://public.stackup.sh/api/v1/node/base-mainnet"
},
oneRpc: {
name: "1RPC",
url: "https://1rpc.io/base"
}
},
tokens: {
eth: {
instanceAddress: {
"0.001": "0x82859DC3697062c16422E9b5e8Ba1B6a6EC72c76",
"0.01": "0xA287c40411685438750a247Ca67488DEBe56EE32",
"0.1": "0x84443CFd09A48AF6eF360C6976C5392aC5023a1F",
"1": "0xd47438C816c9E7f2E2888E060936a499Af9582b3",
"10": "0x330bdFADE01eE9bF63C209Ee33102DD334618e0a",
"100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD"
},
symbol: "ETH",
decimals: 18
},
dai: {
instanceAddress: {
"10": "0x70CC374aE7D1549a4666b7172B78dDCF672B74f7",
"100": "0xD063894588177B8362Dda6C0A7EF09BF6fDF851c",
"1000": "0xa7513fdfF61fc83a9C5c08CE31266e6dd400C54E",
"10000": "0x8f05eDE57098D843F30bE74AC25c292F87b7f775",
"100000": "0xeB7fc86c32e9a5E9DD2a0a78C091b8b625cbee24"
},
instanceApproval: true,
tokenAddress: "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
tokenGasLimit: 7e4,
symbol: "DAI",
decimals: 18,
gasLimit: 7e5
},
tbtc: {
instanceAddress: {
"0.0001": "0x5465800D7Be34dAe2c1572d2227De94dE93B4432",
"0.001": "0xf2d3404c03C8cC0b120bd6E8edD6F69226F03c6d",
"0.01": "0x4261d5209A285410DEa8173B6FE1A0e7BCf20f7c",
"0.1": "0x9FB147F49bFE17D19789547187EAE2406590b217",
"1": "0x2A8515F39716B0C160a3eB32D24E4cbeB76932d2"
},
instanceApproval: true,
tokenAddress: "0x236aa50979D5f3De3Bd1Eeb40E81137F22ab794b",
tokenGasLimit: 7e4,
symbol: "tBTC",
decimals: 18,
gasLimit: 7e5
}
},
relayerEnsSubdomain: "base-tornado",
pollInterval: 2,
constants: {
NOTE_ACCOUNT_BLOCK: 23149794,
ENCRYPTED_NOTES_BLOCK: 23149794
}
},
[81457 /* BLAST */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 1e-3,
fast: 1e-3,
standard: 1e-3,
low: 1e-3
},
nativeCurrency: "eth",
currencyName: "ETH",
explorerUrl: "https://blastscan.io",
merkleTreeHeight: 20,
emptyElement: "21663839004416932945382355908790599225266501822907911457504978515578255421292",
networkName: "Blast",
deployedBlock: 12144065,
stablecoin: "0x4300000000000000000000000000000000000003",
multicallContract: "0xcA11bde05977b3631167028862bE2a173976CA11",
routerContract: "0x0D5550d52428E7e3175bfc9550207e4ad3859b17",
echoContract: "0xa75BF2815618872f155b7C4B0C81bF990f5245E4",
ovmGasPriceOracleContract: "0x420000000000000000000000000000000000000F",
tornadoSubgraph: "tornadocash/blast-tornado-subgraph",
subgraphs: {},
rpcUrls: {
Blast: {
name: "Blast",
url: "https://rpc.blast.io"
},
blastApi: {
name: "BlastApi",
url: "https://blastl2-mainnet.public.blastapi.io"
}
},
tokens: {
eth: {
instanceAddress: {
"0.001": "0x82859DC3697062c16422E9b5e8Ba1B6a6EC72c76",
"0.01": "0xA287c40411685438750a247Ca67488DEBe56EE32",
"0.1": "0x84443CFd09A48AF6eF360C6976C5392aC5023a1F",
"1": "0xd47438C816c9E7f2E2888E060936a499Af9582b3",
"10": "0x330bdFADE01eE9bF63C209Ee33102DD334618e0a",
"100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD"
},
symbol: "ETH",
decimals: 18
}
},
relayerEnsSubdomain: "blast-tornado",
pollInterval: 2,
constants: {
NOTE_ACCOUNT_BLOCK: 12144065,
ENCRYPTED_NOTES_BLOCK: 12144065
}
},
[100 /* GNOSIS */]: { [100 /* GNOSIS */]: {
rpcCallRetryAttempt: 15, rpcCallRetryAttempt: 15,
gasPrices: { gasPrices: {
@ -1435,7 +1243,7 @@ const defaultConfig = {
} }
}, },
relayerEnsSubdomain: "gnosis-tornado", relayerEnsSubdomain: "gnosis-tornado",
pollInterval: 5, pollInterval: 15,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 17754564, NOTE_ACCOUNT_BLOCK: 17754564,
ENCRYPTED_NOTES_BLOCK: 17754564 ENCRYPTED_NOTES_BLOCK: 17754564
@ -1485,7 +1293,7 @@ const defaultConfig = {
} }
}, },
relayerEnsSubdomain: "avalanche-tornado", relayerEnsSubdomain: "avalanche-tornado",
pollInterval: 2, pollInterval: 10,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 4429813, NOTE_ACCOUNT_BLOCK: 4429813,
ENCRYPTED_NOTES_BLOCK: 4429813 ENCRYPTED_NOTES_BLOCK: 4429813
@ -1520,14 +1328,6 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/sepolia-tornado-subgraph", tornadoSubgraph: "tornadocash/sepolia-tornado-subgraph",
subgraphs: {}, subgraphs: {},
rpcUrls: { rpcUrls: {
oneRpc: {
name: "1RPC",
url: "https://1rpc.io/sepolia"
},
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/sepolia"
},
sepolia: { sepolia: {
name: "Sepolia RPC", name: "Sepolia RPC",
url: "https://rpc.sepolia.org" url: "https://rpc.sepolia.org"
@ -1536,6 +1336,10 @@ const defaultConfig = {
name: "Stackup", name: "Stackup",
url: "https://public.stackup.sh/api/v1/node/ethereum-sepolia" url: "https://public.stackup.sh/api/v1/node/ethereum-sepolia"
}, },
oneRpc: {
name: "1RPC",
url: "https://1rpc.io/sepolia"
},
ethpandaops: { ethpandaops: {
name: "ethpandaops", name: "ethpandaops",
url: "https://rpc.sepolia.ethpandaops.io" url: "https://rpc.sepolia.ethpandaops.io"
@ -2429,9 +2233,6 @@ class BaseEventsService {
fromCache: true fromCache: true
}; };
} }
/**
* This may not return in sorted events when called from browser, make sure to sort it again when directly called
*/
async getSavedEvents() { async getSavedEvents() {
let dbEvents = await this.getEventsFromDB(); let dbEvents = await this.getEventsFromDB();
if (!dbEvents.lastBlock) { if (!dbEvents.lastBlock) {
@ -2777,10 +2578,7 @@ class BaseMultiTornadoService extends BaseEventsService {
} }
return acc; return acc;
}, },
{ {}
depositEvents: [],
withdrawalEvents: []
}
); );
return { return {
depositEvents, depositEvents,
@ -3058,12 +2856,7 @@ class BaseGovernanceService extends BaseEventsService {
}); });
} }
async getVotes(proposalId) { async getVotes(proposalId) {
const events = (await this.getSavedEvents()).events.sort((a, b) => { const { events } = await this.getSavedEvents();
if (a.blockNumber === b.blockNumber) {
return a.logIndex - b.logIndex;
}
return a.blockNumber - b.blockNumber;
});
const votedEvents = events.filter( const votedEvents = events.filter(
(e) => e.event === "Voted" && e.proposalId === proposalId (e) => e.event === "Voted" && e.proposalId === proposalId
); );
@ -3092,12 +2885,7 @@ class BaseGovernanceService extends BaseEventsService {
return votes; return votes;
} }
async getDelegatedBalance(ethAccount) { async getDelegatedBalance(ethAccount) {
const events = (await this.getSavedEvents()).events.sort((a, b) => { const { events } = await this.getSavedEvents();
if (a.blockNumber === b.blockNumber) {
return a.logIndex - b.logIndex;
}
return a.blockNumber - b.blockNumber;
});
const delegatedAccs = events.filter((e) => e.event === "Delegated" && e.delegateTo === ethAccount).map((e) => e.account); const delegatedAccs = events.filter((e) => e.event === "Delegated" && e.delegateTo === ethAccount).map((e) => e.account);
const undelegatedAccs = events.filter((e) => e.event === "Undelegated" && e.delegateFrom === ethAccount).map((e) => e.account); const undelegatedAccs = events.filter((e) => e.event === "Undelegated" && e.delegateFrom === ethAccount).map((e) => e.account);
const undel = [...undelegatedAccs]; const undel = [...undelegatedAccs];
@ -3157,13 +2945,6 @@ const staticRelayers = [
hostnames: {}, hostnames: {},
tovarishHost: "tornadowithdraw.com", tovarishHost: "tornadowithdraw.com",
tovarishNetworks: enabledChains tovarishNetworks: enabledChains
},
{
ensName: "rpc.tornadowithdraw.eth",
relayerAddress: "0xFF787B7A5cd8a88508361E3B7bcE791Aa2796526",
hostnames: {},
tovarishHost: "tornadocash-rpc.com",
tovarishNetworks: enabledChains
} }
]; ];
class BaseRegistryService extends BaseEventsService { class BaseRegistryService extends BaseEventsService {
@ -3423,31 +3204,6 @@ RevenueService: Mismatch on withdrawal logs (${withdrawalLogs.length} ) and even
}); });
} }
} }
class BaseTransferService extends BaseEventsService {
constructor(serviceConstructor) {
super({
...serviceConstructor,
contract: serviceConstructor.Token,
type: "Transfer"
});
}
async formatEvents(events) {
return events.map(({ blockNumber, index: logIndex, transactionHash, args }) => {
const { from, to, value } = args;
const eventObjects = {
blockNumber,
logIndex,
transactionHash
};
return {
...eventObjects,
from,
to,
value
};
}).filter((e) => e);
}
}
function zipAsync(file, options) { function zipAsync(file, options) {
return new Promise((res, rej) => { return new Promise((res, rej) => {
@ -3501,11 +3257,11 @@ async function downloadZip({
async function saveDBEvents({ async function saveDBEvents({
idb, idb,
instanceName, instanceName,
newEvents, events,
lastBlock lastBlock
}) { }) {
try { try {
const formattedEvents = newEvents.map((e) => { const formattedEvents = events.map((e) => {
return { return {
eid: `${e.transactionHash}_${e.logIndex}`, eid: `${e.transactionHash}_${e.logIndex}`,
...e ...e
@ -3616,49 +3372,11 @@ class DBTornadoService extends BaseTornadoService {
zipDigest: this.zipDigest zipDigest: this.zipDigest
}); });
} }
async saveEvents({ async saveEvents({ events, lastBlock }) {
newEvents,
lastBlock
}) {
await saveDBEvents({ await saveDBEvents({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock
});
}
}
class DBMultiTornadoService extends BaseMultiTornadoService {
staticUrl;
idb;
zipDigest;
constructor(params) {
super(params);
this.staticUrl = params.staticUrl;
this.idb = params.idb;
}
async getEventsFromDB() {
return await loadDBEvents({
idb: this.idb,
instanceName: this.getInstanceName()
});
}
async getEventsFromCache() {
return await loadRemoteEvents({
staticUrl: this.staticUrl,
instanceName: this.getInstanceName(),
deployedBlock: this.deployedBlock,
zipDigest: this.zipDigest
});
}
async saveEvents({
newEvents,
lastBlock
}) {
await saveDBEvents({
idb: this.idb,
instanceName: this.getInstanceName(),
newEvents,
lastBlock lastBlock
}); });
} }
@ -3686,11 +3404,11 @@ class DBEchoService extends BaseEchoService {
zipDigest: this.zipDigest zipDigest: this.zipDigest
}); });
} }
async saveEvents({ newEvents, lastBlock }) { async saveEvents({ events, lastBlock }) {
await saveDBEvents({ await saveDBEvents({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock lastBlock
}); });
} }
@ -3718,14 +3436,11 @@ class DBEncryptedNotesService extends BaseEncryptedNotesService {
zipDigest: this.zipDigest zipDigest: this.zipDigest
}); });
} }
async saveEvents({ async saveEvents({ events, lastBlock }) {
newEvents,
lastBlock
}) {
await saveDBEvents({ await saveDBEvents({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock lastBlock
}); });
} }
@ -3753,11 +3468,11 @@ class DBGovernanceService extends BaseGovernanceService {
zipDigest: this.zipDigest zipDigest: this.zipDigest
}); });
} }
async saveEvents({ newEvents, lastBlock }) { async saveEvents({ events, lastBlock }) {
await saveDBEvents({ await saveDBEvents({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock lastBlock
}); });
} }
@ -3786,14 +3501,11 @@ class DBRegistryService extends BaseRegistryService {
zipDigest: this.zipDigest zipDigest: this.zipDigest
}); });
} }
async saveEvents({ async saveEvents({ events, lastBlock }) {
newEvents,
lastBlock
}) {
await saveDBEvents({ await saveDBEvents({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock lastBlock
}); });
} }
@ -3882,11 +3594,11 @@ class DBRevenueService extends BaseRevenueService {
zipDigest: this.zipDigest zipDigest: this.zipDigest
}); });
} }
async saveEvents({ newEvents, lastBlock }) { async saveEvents({ events, lastBlock }) {
await saveDBEvents({ await saveDBEvents({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock lastBlock
}); });
} }
@ -9629,7 +9341,7 @@ class TornadoFeeOracle {
* (A single block can bump 12.5% of fees, see the methodology https://hackmd.io/@tvanepps/1559-wallets) * (A single block can bump 12.5% of fees, see the methodology https://hackmd.io/@tvanepps/1559-wallets)
* (Still it is recommended to use 100% premium for sending transactions to prevent stucking it) * (Still it is recommended to use 100% premium for sending transactions to prevent stucking it)
*/ */
async gasPrice(premium) { async gasPrice() {
const [block, getGasPrice, getPriorityFee] = await Promise.all([ const [block, getGasPrice, getPriorityFee] = await Promise.all([
this.provider.getBlock("latest"), this.provider.getBlock("latest"),
(async () => { (async () => {
@ -9647,14 +9359,14 @@ class TornadoFeeOracle {
} }
})() })()
]); ]);
return block?.baseFeePerGas ? block.baseFeePerGas * BigInt(1e4 * (100 + (premium || 50))) / BigInt(1e4 * 100) + getPriorityFee : getGasPrice; return block?.baseFeePerGas ? block.baseFeePerGas * BigInt(15) / BigInt(10) + getPriorityFee : getGasPrice;
} }
/** /**
* Calculate L1 fee for op-stack chains * Calculate L1 fee for op-stack chains
* *
* This is required since relayers would pay the full transaction fees for users * This is required since relayers would pay the full transaction fees for users
*/ */
async fetchL1OptimismFee(tx) { fetchL1OptimismFee(tx) {
if (!this.ovmGasPriceOracle) { if (!this.ovmGasPriceOracle) {
return new Promise((resolve) => resolve(BigInt(0))); return new Promise((resolve) => resolve(BigInt(0)));
} }
@ -9668,7 +9380,7 @@ class TornadoFeeOracle {
to: DUMMY_ADDRESS to: DUMMY_ADDRESS
}; };
} }
return await this.ovmGasPriceOracle.getL1Fee.staticCall(ethers.Transaction.from(tx).unsignedSerialized) * 12n / 10n; return this.ovmGasPriceOracle.getL1Fee.staticCall(ethers.Transaction.from(tx).unsignedSerialized);
} }
/** /**
* We don't need to distinguish default refunds by tokens since most users interact with other defi protocols after withdrawal * We don't need to distinguish default refunds by tokens since most users interact with other defi protocols after withdrawal
@ -9716,8 +9428,6 @@ const gasZipInbounds = {
[NetId.POLYGON]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604", [NetId.POLYGON]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604",
[NetId.OPTIMISM]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604", [NetId.OPTIMISM]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604",
[NetId.ARBITRUM]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604", [NetId.ARBITRUM]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604",
[NetId.BASE]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604",
[NetId.BLAST]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604",
[NetId.GNOSIS]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604", [NetId.GNOSIS]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604",
[NetId.AVALANCHE]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604" [NetId.AVALANCHE]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604"
}; };
@ -9727,8 +9437,6 @@ const gasZipID = {
[NetId.POLYGON]: 17, [NetId.POLYGON]: 17,
[NetId.OPTIMISM]: 55, [NetId.OPTIMISM]: 55,
[NetId.ARBITRUM]: 57, [NetId.ARBITRUM]: 57,
[NetId.BASE]: 54,
[NetId.BLAST]: 96,
[NetId.GNOSIS]: 16, [NetId.GNOSIS]: 16,
[NetId.AVALANCHE]: 15, [NetId.AVALANCHE]: 15,
[NetId.SEPOLIA]: 102 [NetId.SEPOLIA]: 102
@ -9794,7 +9502,7 @@ class IndexedDB {
} }
}; };
this.dbName = dbName; this.dbName = dbName;
this.dbVersion = 36; this.dbVersion = 35;
} }
async initDB() { async initDB() {
try { try {
@ -9990,16 +9698,15 @@ async function getIndexedDB(netId) {
} }
const minimalIndexes = [ const minimalIndexes = [
{ {
name: "eid", name: "blockNumber",
unique: true unique: false
},
{
name: "transactionHash",
unique: false
} }
]; ];
const defaultState = [ const defaultState = [
{
name: `tornado_${netId}`,
keyPath: "eid",
indexes: [...minimalIndexes]
},
{ {
name: `echo_${netId}`, name: `echo_${netId}`,
keyPath: "eid", keyPath: "eid",
@ -10027,7 +9734,8 @@ async function getIndexedDB(netId) {
] ]
} }
]; ];
const { tokens, nativeCurrency, registryContract, governanceContract } = getConfig(netId); const config = getConfig(netId);
const { tokens, nativeCurrency, registryContract, governanceContract } = config;
const stores = [...defaultState]; const stores = [...defaultState];
if (registryContract) { if (registryContract) {
stores.push({ stores.push({
@ -10371,6 +10079,122 @@ async function getPermitSignature({
}) })
); );
} }
async function getPermitCommitmentsSignature({
PermitTornado: PermitTornado2,
Token,
signer,
denomination,
commitments,
nonce
}) {
const value = BigInt(commitments.length) * denomination;
const commitmentsHash = ethers.solidityPackedKeccak256(["bytes32[]"], [commitments]);
return await getPermitSignature({
Token,
signer,
spender: PermitTornado2.target,
value,
nonce,
deadline: BigInt(commitmentsHash)
});
}
async function getPermit2Signature({
Token,
signer,
spender,
value: amount,
nonce,
deadline,
witness
}) {
const sigSigner = signer || Token.runner;
const provider = sigSigner.provider;
const domain = {
name: "Permit2",
chainId: (await provider.getNetwork()).chainId,
verifyingContract: permit2Address
};
const types = !witness ? {
PermitTransferFrom: [
{ name: "permitted", type: "TokenPermissions" },
{ name: "spender", type: "address" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" }
],
TokenPermissions: [
{ name: "token", type: "address" },
{ name: "amount", type: "uint256" }
]
} : {
PermitWitnessTransferFrom: [
{ name: "permitted", type: "TokenPermissions" },
{ name: "spender", type: "address" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" },
{ name: "witness", type: witness.witnessTypeName }
],
TokenPermissions: [
{ name: "token", type: "address" },
{ name: "amount", type: "uint256" }
],
...witness.witnessType
};
const values = {
permitted: {
token: Token.target,
amount
},
spender,
// Sorted nonce are not required for Permit2
nonce: nonce || rBigInt(16),
deadline: deadline || ethers.MaxUint256
};
if (witness) {
values.witness = witness.witness;
}
const hash = new ethers.TypedDataEncoder(types).hash(values);
const signature = ethers.Signature.from(await sigSigner.signTypedData(domain, types, values));
return {
domain,
types,
values,
hash,
signature
};
}
async function getPermit2CommitmentsSignature({
PermitTornado: PermitTornado2,
Token,
signer,
denomination,
commitments,
nonce,
deadline
}) {
const value = BigInt(commitments.length) * denomination;
const commitmentsHash = ethers.solidityPackedKeccak256(["bytes32[]"], [commitments]);
return await getPermit2Signature({
Token,
signer,
spender: PermitTornado2.target,
value,
nonce,
deadline,
witness: {
witnessTypeName: "PermitCommitments",
witnessType: {
PermitCommitments: [
{ name: "instance", type: "address" },
{ name: "commitmentsHash", type: "bytes32" }
]
},
witness: {
instance: PermitTornado2.target,
commitmentsHash
}
}
});
}
class TokenPriceOracle { class TokenPriceOracle {
oracle; oracle;
@ -10811,14 +10635,12 @@ exports.BaseMultiTornadoService = BaseMultiTornadoService;
exports.BaseRegistryService = BaseRegistryService; exports.BaseRegistryService = BaseRegistryService;
exports.BaseRevenueService = BaseRevenueService; exports.BaseRevenueService = BaseRevenueService;
exports.BaseTornadoService = BaseTornadoService; exports.BaseTornadoService = BaseTornadoService;
exports.BaseTransferService = BaseTransferService;
exports.BatchBlockService = BatchBlockService; exports.BatchBlockService = BatchBlockService;
exports.BatchEventsService = BatchEventsService; exports.BatchEventsService = BatchEventsService;
exports.BatchTransactionService = BatchTransactionService; exports.BatchTransactionService = BatchTransactionService;
exports.DBEchoService = DBEchoService; exports.DBEchoService = DBEchoService;
exports.DBEncryptedNotesService = DBEncryptedNotesService; exports.DBEncryptedNotesService = DBEncryptedNotesService;
exports.DBGovernanceService = DBGovernanceService; exports.DBGovernanceService = DBGovernanceService;
exports.DBMultiTornadoService = DBMultiTornadoService;
exports.DBRegistryService = DBRegistryService; exports.DBRegistryService = DBRegistryService;
exports.DBRevenueService = DBRevenueService; exports.DBRevenueService = DBRevenueService;
exports.DBTornadoService = DBTornadoService; exports.DBTornadoService = DBTornadoService;
@ -10903,6 +10725,9 @@ exports.getIndexedDB = getIndexedDB;
exports.getInstanceByAddress = getInstanceByAddress; exports.getInstanceByAddress = getInstanceByAddress;
exports.getMultiInstances = getMultiInstances; exports.getMultiInstances = getMultiInstances;
exports.getNetworkConfig = getNetworkConfig; exports.getNetworkConfig = getNetworkConfig;
exports.getPermit2CommitmentsSignature = getPermit2CommitmentsSignature;
exports.getPermit2Signature = getPermit2Signature;
exports.getPermitCommitmentsSignature = getPermitCommitmentsSignature;
exports.getPermitSignature = getPermitSignature; exports.getPermitSignature = getPermitSignature;
exports.getProvider = getProvider; exports.getProvider = getProvider;
exports.getProviderWithNetId = getProviderWithNetId; exports.getProviderWithNetId = getProviderWithNetId;

524
dist/index.mjs vendored
View File

@ -1,4 +1,4 @@
import { isHexString, assertArgument, assert, EventLog, UndecodedEventLog, Log, FetchRequest, JsonRpcProvider, Network, EnsPlugin, GasCostPlugin, Wallet, HDNodeWallet, VoidSigner, JsonRpcSigner, BrowserProvider, isAddress, parseEther, getAddress, AbiCoder, formatEther, namehash, dataSlice, dataLength, Interface, Contract, computeAddress, keccak256, EnsResolver, parseUnits, Transaction, Signature, MaxUint256, ZeroAddress } from 'ethers'; import { isHexString, assertArgument, assert, EventLog, UndecodedEventLog, Log, FetchRequest, JsonRpcProvider, Network, EnsPlugin, GasCostPlugin, Wallet, HDNodeWallet, VoidSigner, JsonRpcSigner, BrowserProvider, isAddress, parseEther, getAddress, AbiCoder, formatEther, namehash, dataSlice, dataLength, Interface, Contract, computeAddress, keccak256, EnsResolver, parseUnits, Transaction, Signature, MaxUint256, solidityPackedKeccak256, TypedDataEncoder, ZeroAddress } from 'ethers';
import { Tornado__factory } from '@tornado/contracts'; import { Tornado__factory } from '@tornado/contracts';
import { webcrypto } from 'crypto'; import { webcrypto } from 'crypto';
import BN from 'bn.js'; import BN from 'bn.js';
@ -10,9 +10,9 @@ import { buildPedersenHash, buildMimcSponge } from 'circomlibjs';
import { getEncryptionPublicKey, encrypt, decrypt } from '@metamask/eth-sig-util'; import { getEncryptionPublicKey, encrypt, decrypt } from '@metamask/eth-sig-util';
import { openDB, deleteDB } from 'idb'; import { openDB, deleteDB } from 'idb';
import { Worker as Worker$1 } from 'worker_threads'; import { Worker as Worker$1 } from 'worker_threads';
import { MerkleTree, PartialMerkleTree } from 'fixed-merkle-tree'; import { MerkleTree, PartialMerkleTree } from '@tornado/fixed-merkle-tree';
import * as websnarkUtils from 'websnark/src/utils'; import * as websnarkUtils from '@tornado/websnark/src/utils';
import websnarkGroth from 'websnark/src/groth16'; import websnarkGroth from '@tornado/websnark/src/groth16';
BigInt.prototype.toJSON = function() { BigInt.prototype.toJSON = function() {
return this.toString(); return this.toString();
@ -677,7 +677,7 @@ function getProviderWithNetId(netId, rpcUrl, config, fetchOptions) {
return provider; return provider;
} }
const populateTransaction = async (signer, tx) => { const populateTransaction = async (signer, tx) => {
const provider = signer.readonlyProvider || signer.provider; const provider = signer.provider;
if (!tx.from) { if (!tx.from) {
tx.from = signer.address; tx.from = signer.address;
} else if (tx.from !== signer.address) { } else if (tx.from !== signer.address) {
@ -772,14 +772,12 @@ class TornadoRpcSigner extends JsonRpcSigner {
gasLimitBump; gasLimitBump;
gasFailover; gasFailover;
bumpNonce; bumpNonce;
readonlyProvider; constructor(provider, address, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce } = {}) {
constructor(provider, address, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce, readonlyProvider } = {}) {
super(provider, address); super(provider, address);
this.gasPriceBump = gasPriceBump ?? 0; this.gasPriceBump = gasPriceBump ?? 0;
this.gasLimitBump = gasLimitBump ?? 3e3; this.gasLimitBump = gasLimitBump ?? 3e3;
this.gasFailover = gasFailover ?? false; this.gasFailover = gasFailover ?? false;
this.bumpNonce = bumpNonce ?? false; this.bumpNonce = bumpNonce ?? false;
this.readonlyProvider = readonlyProvider;
} }
async sendUncheckedTransaction(tx) { async sendUncheckedTransaction(tx) {
return super.sendUncheckedTransaction(await populateTransaction(this, tx)); return super.sendUncheckedTransaction(await populateTransaction(this, tx));
@ -815,8 +813,6 @@ var NetId = /* @__PURE__ */ ((NetId2) => {
NetId2[NetId2["POLYGON"] = 137] = "POLYGON"; NetId2[NetId2["POLYGON"] = 137] = "POLYGON";
NetId2[NetId2["OPTIMISM"] = 10] = "OPTIMISM"; NetId2[NetId2["OPTIMISM"] = 10] = "OPTIMISM";
NetId2[NetId2["ARBITRUM"] = 42161] = "ARBITRUM"; NetId2[NetId2["ARBITRUM"] = 42161] = "ARBITRUM";
NetId2[NetId2["BASE"] = 8453] = "BASE";
NetId2[NetId2["BLAST"] = 81457] = "BLAST";
NetId2[NetId2["GNOSIS"] = 100] = "GNOSIS"; NetId2[NetId2["GNOSIS"] = 100] = "GNOSIS";
NetId2[NetId2["AVALANCHE"] = 43114] = "AVALANCHE"; NetId2[NetId2["AVALANCHE"] = 43114] = "AVALANCHE";
NetId2[NetId2["SEPOLIA"] = 11155111] = "SEPOLIA"; NetId2[NetId2["SEPOLIA"] = 11155111] = "SEPOLIA";
@ -843,10 +839,6 @@ const defaultConfig = {
name: "MEV Blocker", name: "MEV Blocker",
url: "https://rpc.mevblocker.io" url: "https://rpc.mevblocker.io"
}, },
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com"
},
keydonix: { keydonix: {
name: "Horswap ( Keydonix )", name: "Horswap ( Keydonix )",
url: "https://ethereum.keydonix.com/v1/mainnet" url: "https://ethereum.keydonix.com/v1/mainnet"
@ -966,10 +958,10 @@ const defaultConfig = {
[56 /* BSC */]: { [56 /* BSC */]: {
rpcCallRetryAttempt: 15, rpcCallRetryAttempt: 15,
gasPrices: { gasPrices: {
instant: 3, instant: 5,
fast: 1, fast: 5,
standard: 1, standard: 5,
low: 1 low: 5
}, },
nativeCurrency: "bnb", nativeCurrency: "bnb",
currencyName: "BNB", currencyName: "BNB",
@ -994,10 +986,6 @@ const defaultConfig = {
name: "BNB Chain 2", name: "BNB Chain 2",
url: "https://bsc-dataseed1.ninicoin.io" url: "https://bsc-dataseed1.ninicoin.io"
}, },
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/bsc"
},
nodereal: { nodereal: {
name: "NodeReal", name: "NodeReal",
url: "https://binance.nodereal.io" url: "https://binance.nodereal.io"
@ -1021,39 +1009,10 @@ const defaultConfig = {
}, },
symbol: "BNB", symbol: "BNB",
decimals: 18 decimals: 18
},
usdt: {
instanceAddress: {
"10": "0x261fB4f84bb0BdEe7E035B6a8a08e5c35AdacdDD",
"100": "0x3957861d4897d883C9b944C0b4E22bBd0DDE6e21",
"1000": "0x6D180403AdFb39F70983eB51A033C5e52eb9BB69",
"10000": "0x3722662D8AaB07B216B14C02eF0ee940d14A4200"
},
instanceApproval: true,
tokenAddress: "0x55d398326f99059fF775485246999027B3197955",
tokenGasLimit: 7e4,
symbol: "USDT",
decimals: 18,
gasLimit: 7e5
},
btcb: {
instanceAddress: {
"0.0001": "0x736dABbFc8101Ae75287104eCcf67e45D7369Ae1",
"0.001": "0x82c7Ce6f1F158cEC5536d591a2BC19864b3CA823",
"0.01": "0x8284c96679037d8081E498d8F767cA5a140BFAAf",
"0.1": "0x2bcD128Ce23ee30Ee945E613ff129c4DE1102C79"
},
instanceApproval: true,
tokenAddress: "0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c",
tokenGasLimit: 7e4,
symbol: "BTCB",
decimals: 18,
gasLimit: 7e5
} }
}, },
optionalTokens: ["usdt", "btcb"],
relayerEnsSubdomain: "bsc-tornado", relayerEnsSubdomain: "bsc-tornado",
pollInterval: 3, pollInterval: 10,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 8159269, NOTE_ACCOUNT_BLOCK: 8159269,
ENCRYPTED_NOTES_BLOCK: 8159269 ENCRYPTED_NOTES_BLOCK: 8159269
@ -1062,9 +1021,9 @@ const defaultConfig = {
[137 /* POLYGON */]: { [137 /* POLYGON */]: {
rpcCallRetryAttempt: 15, rpcCallRetryAttempt: 15,
gasPrices: { gasPrices: {
instant: 60, instant: 100,
fast: 30, fast: 75,
standard: 30, standard: 50,
low: 30 low: 30
}, },
nativeCurrency: "matic", nativeCurrency: "matic",
@ -1104,7 +1063,7 @@ const defaultConfig = {
} }
}, },
relayerEnsSubdomain: "polygon-tornado", relayerEnsSubdomain: "polygon-tornado",
pollInterval: 2, pollInterval: 10,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 16257996, NOTE_ACCOUNT_BLOCK: 16257996,
ENCRYPTED_NOTES_BLOCK: 16257996 ENCRYPTED_NOTES_BLOCK: 16257996
@ -1146,20 +1105,17 @@ const defaultConfig = {
tokens: { tokens: {
eth: { eth: {
instanceAddress: { instanceAddress: {
"0.001": "0x82859DC3697062c16422E9b5e8Ba1B6a6EC72c76",
"0.01": "0xA287c40411685438750a247Ca67488DEBe56EE32",
"0.1": "0x84443CFd09A48AF6eF360C6976C5392aC5023a1F", "0.1": "0x84443CFd09A48AF6eF360C6976C5392aC5023a1F",
"1": "0xd47438C816c9E7f2E2888E060936a499Af9582b3", "1": "0xd47438C816c9E7f2E2888E060936a499Af9582b3",
"10": "0x330bdFADE01eE9bF63C209Ee33102DD334618e0a", "10": "0x330bdFADE01eE9bF63C209Ee33102DD334618e0a",
"100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD" "100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD"
}, },
optionalInstances: ["0.001", "0.01"],
symbol: "ETH", symbol: "ETH",
decimals: 18 decimals: 18
} }
}, },
relayerEnsSubdomain: "optimism-tornado", relayerEnsSubdomain: "optimism-tornado",
pollInterval: 2, pollInterval: 15,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 2243694, NOTE_ACCOUNT_BLOCK: 2243694,
ENCRYPTED_NOTES_BLOCK: 2243694 ENCRYPTED_NOTES_BLOCK: 2243694
@ -1168,10 +1124,10 @@ const defaultConfig = {
[42161 /* ARBITRUM */]: { [42161 /* ARBITRUM */]: {
rpcCallRetryAttempt: 15, rpcCallRetryAttempt: 15,
gasPrices: { gasPrices: {
instant: 0.02, instant: 4,
fast: 0.02, fast: 3,
standard: 0.02, standard: 2.52,
low: 0.02 low: 2.29
}, },
nativeCurrency: "eth", nativeCurrency: "eth",
currencyName: "ETH", currencyName: "ETH",
@ -1192,10 +1148,6 @@ const defaultConfig = {
name: "Arbitrum", name: "Arbitrum",
url: "https://arb1.arbitrum.io/rpc" url: "https://arb1.arbitrum.io/rpc"
}, },
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/arbitrum"
},
stackup: { stackup: {
name: "Stackup", name: "Stackup",
url: "https://public.stackup.sh/api/v1/node/arbitrum-one" url: "https://public.stackup.sh/api/v1/node/arbitrum-one"
@ -1208,166 +1160,22 @@ const defaultConfig = {
tokens: { tokens: {
eth: { eth: {
instanceAddress: { instanceAddress: {
"0.001": "0x82859DC3697062c16422E9b5e8Ba1B6a6EC72c76",
"0.01": "0xA287c40411685438750a247Ca67488DEBe56EE32",
"0.1": "0x84443CFd09A48AF6eF360C6976C5392aC5023a1F", "0.1": "0x84443CFd09A48AF6eF360C6976C5392aC5023a1F",
"1": "0xd47438C816c9E7f2E2888E060936a499Af9582b3", "1": "0xd47438C816c9E7f2E2888E060936a499Af9582b3",
"10": "0x330bdFADE01eE9bF63C209Ee33102DD334618e0a", "10": "0x330bdFADE01eE9bF63C209Ee33102DD334618e0a",
"100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD" "100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD"
}, },
optionalInstances: ["0.001", "0.01"],
symbol: "ETH", symbol: "ETH",
decimals: 18 decimals: 18
} }
}, },
relayerEnsSubdomain: "arbitrum-tornado", relayerEnsSubdomain: "arbitrum-tornado",
pollInterval: 2, pollInterval: 15,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 3430605, NOTE_ACCOUNT_BLOCK: 3430605,
ENCRYPTED_NOTES_BLOCK: 3430605 ENCRYPTED_NOTES_BLOCK: 3430605
} }
}, },
[8453 /* BASE */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 0.1,
fast: 0.06,
standard: 0.05,
low: 0.02
},
nativeCurrency: "eth",
currencyName: "ETH",
explorerUrl: "https://basescan.org",
merkleTreeHeight: 20,
emptyElement: "21663839004416932945382355908790599225266501822907911457504978515578255421292",
networkName: "Base",
deployedBlock: 23149794,
stablecoin: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
multicallContract: "0xcA11bde05977b3631167028862bE2a173976CA11",
routerContract: "0x0D5550d52428E7e3175bfc9550207e4ad3859b17",
echoContract: "0xa75BF2815618872f155b7C4B0C81bF990f5245E4",
offchainOracleContract: "0x00000000000D6FFc74A8feb35aF5827bf57f6786",
ovmGasPriceOracleContract: "0x420000000000000000000000000000000000000F",
tornadoSubgraph: "tornadocash/base-tornado-subgraph",
subgraphs: {},
rpcUrls: {
Base: {
name: "Base",
url: "https://mainnet.base.org"
},
stackup: {
name: "Stackup",
url: "https://public.stackup.sh/api/v1/node/base-mainnet"
},
oneRpc: {
name: "1RPC",
url: "https://1rpc.io/base"
}
},
tokens: {
eth: {
instanceAddress: {
"0.001": "0x82859DC3697062c16422E9b5e8Ba1B6a6EC72c76",
"0.01": "0xA287c40411685438750a247Ca67488DEBe56EE32",
"0.1": "0x84443CFd09A48AF6eF360C6976C5392aC5023a1F",
"1": "0xd47438C816c9E7f2E2888E060936a499Af9582b3",
"10": "0x330bdFADE01eE9bF63C209Ee33102DD334618e0a",
"100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD"
},
symbol: "ETH",
decimals: 18
},
dai: {
instanceAddress: {
"10": "0x70CC374aE7D1549a4666b7172B78dDCF672B74f7",
"100": "0xD063894588177B8362Dda6C0A7EF09BF6fDF851c",
"1000": "0xa7513fdfF61fc83a9C5c08CE31266e6dd400C54E",
"10000": "0x8f05eDE57098D843F30bE74AC25c292F87b7f775",
"100000": "0xeB7fc86c32e9a5E9DD2a0a78C091b8b625cbee24"
},
instanceApproval: true,
tokenAddress: "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
tokenGasLimit: 7e4,
symbol: "DAI",
decimals: 18,
gasLimit: 7e5
},
tbtc: {
instanceAddress: {
"0.0001": "0x5465800D7Be34dAe2c1572d2227De94dE93B4432",
"0.001": "0xf2d3404c03C8cC0b120bd6E8edD6F69226F03c6d",
"0.01": "0x4261d5209A285410DEa8173B6FE1A0e7BCf20f7c",
"0.1": "0x9FB147F49bFE17D19789547187EAE2406590b217",
"1": "0x2A8515F39716B0C160a3eB32D24E4cbeB76932d2"
},
instanceApproval: true,
tokenAddress: "0x236aa50979D5f3De3Bd1Eeb40E81137F22ab794b",
tokenGasLimit: 7e4,
symbol: "tBTC",
decimals: 18,
gasLimit: 7e5
}
},
relayerEnsSubdomain: "base-tornado",
pollInterval: 2,
constants: {
NOTE_ACCOUNT_BLOCK: 23149794,
ENCRYPTED_NOTES_BLOCK: 23149794
}
},
[81457 /* BLAST */]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 1e-3,
fast: 1e-3,
standard: 1e-3,
low: 1e-3
},
nativeCurrency: "eth",
currencyName: "ETH",
explorerUrl: "https://blastscan.io",
merkleTreeHeight: 20,
emptyElement: "21663839004416932945382355908790599225266501822907911457504978515578255421292",
networkName: "Blast",
deployedBlock: 12144065,
stablecoin: "0x4300000000000000000000000000000000000003",
multicallContract: "0xcA11bde05977b3631167028862bE2a173976CA11",
routerContract: "0x0D5550d52428E7e3175bfc9550207e4ad3859b17",
echoContract: "0xa75BF2815618872f155b7C4B0C81bF990f5245E4",
ovmGasPriceOracleContract: "0x420000000000000000000000000000000000000F",
tornadoSubgraph: "tornadocash/blast-tornado-subgraph",
subgraphs: {},
rpcUrls: {
Blast: {
name: "Blast",
url: "https://rpc.blast.io"
},
blastApi: {
name: "BlastApi",
url: "https://blastl2-mainnet.public.blastapi.io"
}
},
tokens: {
eth: {
instanceAddress: {
"0.001": "0x82859DC3697062c16422E9b5e8Ba1B6a6EC72c76",
"0.01": "0xA287c40411685438750a247Ca67488DEBe56EE32",
"0.1": "0x84443CFd09A48AF6eF360C6976C5392aC5023a1F",
"1": "0xd47438C816c9E7f2E2888E060936a499Af9582b3",
"10": "0x330bdFADE01eE9bF63C209Ee33102DD334618e0a",
"100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD"
},
symbol: "ETH",
decimals: 18
}
},
relayerEnsSubdomain: "blast-tornado",
pollInterval: 2,
constants: {
NOTE_ACCOUNT_BLOCK: 12144065,
ENCRYPTED_NOTES_BLOCK: 12144065
}
},
[100 /* GNOSIS */]: { [100 /* GNOSIS */]: {
rpcCallRetryAttempt: 15, rpcCallRetryAttempt: 15,
gasPrices: { gasPrices: {
@ -1413,7 +1221,7 @@ const defaultConfig = {
} }
}, },
relayerEnsSubdomain: "gnosis-tornado", relayerEnsSubdomain: "gnosis-tornado",
pollInterval: 5, pollInterval: 15,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 17754564, NOTE_ACCOUNT_BLOCK: 17754564,
ENCRYPTED_NOTES_BLOCK: 17754564 ENCRYPTED_NOTES_BLOCK: 17754564
@ -1463,7 +1271,7 @@ const defaultConfig = {
} }
}, },
relayerEnsSubdomain: "avalanche-tornado", relayerEnsSubdomain: "avalanche-tornado",
pollInterval: 2, pollInterval: 10,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 4429813, NOTE_ACCOUNT_BLOCK: 4429813,
ENCRYPTED_NOTES_BLOCK: 4429813 ENCRYPTED_NOTES_BLOCK: 4429813
@ -1498,14 +1306,6 @@ const defaultConfig = {
tornadoSubgraph: "tornadocash/sepolia-tornado-subgraph", tornadoSubgraph: "tornadocash/sepolia-tornado-subgraph",
subgraphs: {}, subgraphs: {},
rpcUrls: { rpcUrls: {
oneRpc: {
name: "1RPC",
url: "https://1rpc.io/sepolia"
},
tornadoRpc: {
name: "Tornado RPC",
url: "https://tornadocash-rpc.com/sepolia"
},
sepolia: { sepolia: {
name: "Sepolia RPC", name: "Sepolia RPC",
url: "https://rpc.sepolia.org" url: "https://rpc.sepolia.org"
@ -1514,6 +1314,10 @@ const defaultConfig = {
name: "Stackup", name: "Stackup",
url: "https://public.stackup.sh/api/v1/node/ethereum-sepolia" url: "https://public.stackup.sh/api/v1/node/ethereum-sepolia"
}, },
oneRpc: {
name: "1RPC",
url: "https://1rpc.io/sepolia"
},
ethpandaops: { ethpandaops: {
name: "ethpandaops", name: "ethpandaops",
url: "https://rpc.sepolia.ethpandaops.io" url: "https://rpc.sepolia.ethpandaops.io"
@ -2407,9 +2211,6 @@ class BaseEventsService {
fromCache: true fromCache: true
}; };
} }
/**
* This may not return in sorted events when called from browser, make sure to sort it again when directly called
*/
async getSavedEvents() { async getSavedEvents() {
let dbEvents = await this.getEventsFromDB(); let dbEvents = await this.getEventsFromDB();
if (!dbEvents.lastBlock) { if (!dbEvents.lastBlock) {
@ -2755,10 +2556,7 @@ class BaseMultiTornadoService extends BaseEventsService {
} }
return acc; return acc;
}, },
{ {}
depositEvents: [],
withdrawalEvents: []
}
); );
return { return {
depositEvents, depositEvents,
@ -3036,12 +2834,7 @@ class BaseGovernanceService extends BaseEventsService {
}); });
} }
async getVotes(proposalId) { async getVotes(proposalId) {
const events = (await this.getSavedEvents()).events.sort((a, b) => { const { events } = await this.getSavedEvents();
if (a.blockNumber === b.blockNumber) {
return a.logIndex - b.logIndex;
}
return a.blockNumber - b.blockNumber;
});
const votedEvents = events.filter( const votedEvents = events.filter(
(e) => e.event === "Voted" && e.proposalId === proposalId (e) => e.event === "Voted" && e.proposalId === proposalId
); );
@ -3070,12 +2863,7 @@ class BaseGovernanceService extends BaseEventsService {
return votes; return votes;
} }
async getDelegatedBalance(ethAccount) { async getDelegatedBalance(ethAccount) {
const events = (await this.getSavedEvents()).events.sort((a, b) => { const { events } = await this.getSavedEvents();
if (a.blockNumber === b.blockNumber) {
return a.logIndex - b.logIndex;
}
return a.blockNumber - b.blockNumber;
});
const delegatedAccs = events.filter((e) => e.event === "Delegated" && e.delegateTo === ethAccount).map((e) => e.account); const delegatedAccs = events.filter((e) => e.event === "Delegated" && e.delegateTo === ethAccount).map((e) => e.account);
const undelegatedAccs = events.filter((e) => e.event === "Undelegated" && e.delegateFrom === ethAccount).map((e) => e.account); const undelegatedAccs = events.filter((e) => e.event === "Undelegated" && e.delegateFrom === ethAccount).map((e) => e.account);
const undel = [...undelegatedAccs]; const undel = [...undelegatedAccs];
@ -3135,13 +2923,6 @@ const staticRelayers = [
hostnames: {}, hostnames: {},
tovarishHost: "tornadowithdraw.com", tovarishHost: "tornadowithdraw.com",
tovarishNetworks: enabledChains tovarishNetworks: enabledChains
},
{
ensName: "rpc.tornadowithdraw.eth",
relayerAddress: "0xFF787B7A5cd8a88508361E3B7bcE791Aa2796526",
hostnames: {},
tovarishHost: "tornadocash-rpc.com",
tovarishNetworks: enabledChains
} }
]; ];
class BaseRegistryService extends BaseEventsService { class BaseRegistryService extends BaseEventsService {
@ -3401,31 +3182,6 @@ RevenueService: Mismatch on withdrawal logs (${withdrawalLogs.length} ) and even
}); });
} }
} }
class BaseTransferService extends BaseEventsService {
constructor(serviceConstructor) {
super({
...serviceConstructor,
contract: serviceConstructor.Token,
type: "Transfer"
});
}
async formatEvents(events) {
return events.map(({ blockNumber, index: logIndex, transactionHash, args }) => {
const { from, to, value } = args;
const eventObjects = {
blockNumber,
logIndex,
transactionHash
};
return {
...eventObjects,
from,
to,
value
};
}).filter((e) => e);
}
}
function zipAsync(file, options) { function zipAsync(file, options) {
return new Promise((res, rej) => { return new Promise((res, rej) => {
@ -3479,11 +3235,11 @@ async function downloadZip({
async function saveDBEvents({ async function saveDBEvents({
idb, idb,
instanceName, instanceName,
newEvents, events,
lastBlock lastBlock
}) { }) {
try { try {
const formattedEvents = newEvents.map((e) => { const formattedEvents = events.map((e) => {
return { return {
eid: `${e.transactionHash}_${e.logIndex}`, eid: `${e.transactionHash}_${e.logIndex}`,
...e ...e
@ -3594,49 +3350,11 @@ class DBTornadoService extends BaseTornadoService {
zipDigest: this.zipDigest zipDigest: this.zipDigest
}); });
} }
async saveEvents({ async saveEvents({ events, lastBlock }) {
newEvents,
lastBlock
}) {
await saveDBEvents({ await saveDBEvents({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock
});
}
}
class DBMultiTornadoService extends BaseMultiTornadoService {
staticUrl;
idb;
zipDigest;
constructor(params) {
super(params);
this.staticUrl = params.staticUrl;
this.idb = params.idb;
}
async getEventsFromDB() {
return await loadDBEvents({
idb: this.idb,
instanceName: this.getInstanceName()
});
}
async getEventsFromCache() {
return await loadRemoteEvents({
staticUrl: this.staticUrl,
instanceName: this.getInstanceName(),
deployedBlock: this.deployedBlock,
zipDigest: this.zipDigest
});
}
async saveEvents({
newEvents,
lastBlock
}) {
await saveDBEvents({
idb: this.idb,
instanceName: this.getInstanceName(),
newEvents,
lastBlock lastBlock
}); });
} }
@ -3664,11 +3382,11 @@ class DBEchoService extends BaseEchoService {
zipDigest: this.zipDigest zipDigest: this.zipDigest
}); });
} }
async saveEvents({ newEvents, lastBlock }) { async saveEvents({ events, lastBlock }) {
await saveDBEvents({ await saveDBEvents({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock lastBlock
}); });
} }
@ -3696,14 +3414,11 @@ class DBEncryptedNotesService extends BaseEncryptedNotesService {
zipDigest: this.zipDigest zipDigest: this.zipDigest
}); });
} }
async saveEvents({ async saveEvents({ events, lastBlock }) {
newEvents,
lastBlock
}) {
await saveDBEvents({ await saveDBEvents({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock lastBlock
}); });
} }
@ -3731,11 +3446,11 @@ class DBGovernanceService extends BaseGovernanceService {
zipDigest: this.zipDigest zipDigest: this.zipDigest
}); });
} }
async saveEvents({ newEvents, lastBlock }) { async saveEvents({ events, lastBlock }) {
await saveDBEvents({ await saveDBEvents({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock lastBlock
}); });
} }
@ -3764,14 +3479,11 @@ class DBRegistryService extends BaseRegistryService {
zipDigest: this.zipDigest zipDigest: this.zipDigest
}); });
} }
async saveEvents({ async saveEvents({ events, lastBlock }) {
newEvents,
lastBlock
}) {
await saveDBEvents({ await saveDBEvents({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock lastBlock
}); });
} }
@ -3860,11 +3572,11 @@ class DBRevenueService extends BaseRevenueService {
zipDigest: this.zipDigest zipDigest: this.zipDigest
}); });
} }
async saveEvents({ newEvents, lastBlock }) { async saveEvents({ events, lastBlock }) {
await saveDBEvents({ await saveDBEvents({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock lastBlock
}); });
} }
@ -9607,7 +9319,7 @@ class TornadoFeeOracle {
* (A single block can bump 12.5% of fees, see the methodology https://hackmd.io/@tvanepps/1559-wallets) * (A single block can bump 12.5% of fees, see the methodology https://hackmd.io/@tvanepps/1559-wallets)
* (Still it is recommended to use 100% premium for sending transactions to prevent stucking it) * (Still it is recommended to use 100% premium for sending transactions to prevent stucking it)
*/ */
async gasPrice(premium) { async gasPrice() {
const [block, getGasPrice, getPriorityFee] = await Promise.all([ const [block, getGasPrice, getPriorityFee] = await Promise.all([
this.provider.getBlock("latest"), this.provider.getBlock("latest"),
(async () => { (async () => {
@ -9625,14 +9337,14 @@ class TornadoFeeOracle {
} }
})() })()
]); ]);
return block?.baseFeePerGas ? block.baseFeePerGas * BigInt(1e4 * (100 + (premium || 50))) / BigInt(1e4 * 100) + getPriorityFee : getGasPrice; return block?.baseFeePerGas ? block.baseFeePerGas * BigInt(15) / BigInt(10) + getPriorityFee : getGasPrice;
} }
/** /**
* Calculate L1 fee for op-stack chains * Calculate L1 fee for op-stack chains
* *
* This is required since relayers would pay the full transaction fees for users * This is required since relayers would pay the full transaction fees for users
*/ */
async fetchL1OptimismFee(tx) { fetchL1OptimismFee(tx) {
if (!this.ovmGasPriceOracle) { if (!this.ovmGasPriceOracle) {
return new Promise((resolve) => resolve(BigInt(0))); return new Promise((resolve) => resolve(BigInt(0)));
} }
@ -9646,7 +9358,7 @@ class TornadoFeeOracle {
to: DUMMY_ADDRESS to: DUMMY_ADDRESS
}; };
} }
return await this.ovmGasPriceOracle.getL1Fee.staticCall(Transaction.from(tx).unsignedSerialized) * 12n / 10n; return this.ovmGasPriceOracle.getL1Fee.staticCall(Transaction.from(tx).unsignedSerialized);
} }
/** /**
* We don't need to distinguish default refunds by tokens since most users interact with other defi protocols after withdrawal * We don't need to distinguish default refunds by tokens since most users interact with other defi protocols after withdrawal
@ -9694,8 +9406,6 @@ const gasZipInbounds = {
[NetId.POLYGON]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604", [NetId.POLYGON]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604",
[NetId.OPTIMISM]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604", [NetId.OPTIMISM]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604",
[NetId.ARBITRUM]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604", [NetId.ARBITRUM]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604",
[NetId.BASE]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604",
[NetId.BLAST]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604",
[NetId.GNOSIS]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604", [NetId.GNOSIS]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604",
[NetId.AVALANCHE]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604" [NetId.AVALANCHE]: "0x391E7C679d29bD940d63be94AD22A25d25b5A604"
}; };
@ -9705,8 +9415,6 @@ const gasZipID = {
[NetId.POLYGON]: 17, [NetId.POLYGON]: 17,
[NetId.OPTIMISM]: 55, [NetId.OPTIMISM]: 55,
[NetId.ARBITRUM]: 57, [NetId.ARBITRUM]: 57,
[NetId.BASE]: 54,
[NetId.BLAST]: 96,
[NetId.GNOSIS]: 16, [NetId.GNOSIS]: 16,
[NetId.AVALANCHE]: 15, [NetId.AVALANCHE]: 15,
[NetId.SEPOLIA]: 102 [NetId.SEPOLIA]: 102
@ -9772,7 +9480,7 @@ class IndexedDB {
} }
}; };
this.dbName = dbName; this.dbName = dbName;
this.dbVersion = 36; this.dbVersion = 35;
} }
async initDB() { async initDB() {
try { try {
@ -9968,16 +9676,15 @@ async function getIndexedDB(netId) {
} }
const minimalIndexes = [ const minimalIndexes = [
{ {
name: "eid", name: "blockNumber",
unique: true unique: false
},
{
name: "transactionHash",
unique: false
} }
]; ];
const defaultState = [ const defaultState = [
{
name: `tornado_${netId}`,
keyPath: "eid",
indexes: [...minimalIndexes]
},
{ {
name: `echo_${netId}`, name: `echo_${netId}`,
keyPath: "eid", keyPath: "eid",
@ -10005,7 +9712,8 @@ async function getIndexedDB(netId) {
] ]
} }
]; ];
const { tokens, nativeCurrency, registryContract, governanceContract } = getConfig(netId); const config = getConfig(netId);
const { tokens, nativeCurrency, registryContract, governanceContract } = config;
const stores = [...defaultState]; const stores = [...defaultState];
if (registryContract) { if (registryContract) {
stores.push({ stores.push({
@ -10349,6 +10057,122 @@ async function getPermitSignature({
}) })
); );
} }
async function getPermitCommitmentsSignature({
PermitTornado: PermitTornado2,
Token,
signer,
denomination,
commitments,
nonce
}) {
const value = BigInt(commitments.length) * denomination;
const commitmentsHash = solidityPackedKeccak256(["bytes32[]"], [commitments]);
return await getPermitSignature({
Token,
signer,
spender: PermitTornado2.target,
value,
nonce,
deadline: BigInt(commitmentsHash)
});
}
async function getPermit2Signature({
Token,
signer,
spender,
value: amount,
nonce,
deadline,
witness
}) {
const sigSigner = signer || Token.runner;
const provider = sigSigner.provider;
const domain = {
name: "Permit2",
chainId: (await provider.getNetwork()).chainId,
verifyingContract: permit2Address
};
const types = !witness ? {
PermitTransferFrom: [
{ name: "permitted", type: "TokenPermissions" },
{ name: "spender", type: "address" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" }
],
TokenPermissions: [
{ name: "token", type: "address" },
{ name: "amount", type: "uint256" }
]
} : {
PermitWitnessTransferFrom: [
{ name: "permitted", type: "TokenPermissions" },
{ name: "spender", type: "address" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" },
{ name: "witness", type: witness.witnessTypeName }
],
TokenPermissions: [
{ name: "token", type: "address" },
{ name: "amount", type: "uint256" }
],
...witness.witnessType
};
const values = {
permitted: {
token: Token.target,
amount
},
spender,
// Sorted nonce are not required for Permit2
nonce: nonce || rBigInt(16),
deadline: deadline || MaxUint256
};
if (witness) {
values.witness = witness.witness;
}
const hash = new TypedDataEncoder(types).hash(values);
const signature = Signature.from(await sigSigner.signTypedData(domain, types, values));
return {
domain,
types,
values,
hash,
signature
};
}
async function getPermit2CommitmentsSignature({
PermitTornado: PermitTornado2,
Token,
signer,
denomination,
commitments,
nonce,
deadline
}) {
const value = BigInt(commitments.length) * denomination;
const commitmentsHash = solidityPackedKeccak256(["bytes32[]"], [commitments]);
return await getPermit2Signature({
Token,
signer,
spender: PermitTornado2.target,
value,
nonce,
deadline,
witness: {
witnessTypeName: "PermitCommitments",
witnessType: {
PermitCommitments: [
{ name: "instance", type: "address" },
{ name: "commitmentsHash", type: "bytes32" }
]
},
witness: {
instance: PermitTornado2.target,
commitmentsHash
}
}
});
}
class TokenPriceOracle { class TokenPriceOracle {
oracle; oracle;
@ -10781,4 +10605,4 @@ async function calculateSnarkProof(input, circuit, provingKey) {
return { proof, args }; return { proof, args };
} }
export { BaseEchoService, BaseEncryptedNotesService, BaseEventsService, BaseGovernanceService, BaseMultiTornadoService, BaseRegistryService, BaseRevenueService, BaseTornadoService, BaseTransferService, BatchBlockService, BatchEventsService, BatchTransactionService, DBEchoService, DBEncryptedNotesService, DBGovernanceService, DBMultiTornadoService, DBRegistryService, DBRevenueService, DBTornadoService, Deposit, ENSNameWrapper__factory, ENSRegistry__factory, ENSResolver__factory, ENSUtils, ENS__factory, ERC20__factory, EnsContracts, INDEX_DB_ERROR, IndexedDB, Invoice, MAX_FEE, MAX_TOVARISH_EVENTS, MIN_FEE, MIN_STAKE_BALANCE, MerkleTreeService, Mimc, Multicall__factory, NetId, NoteAccount, OffchainOracle__factory, OvmGasPriceOracle__factory, Pedersen, RelayerClient, ReverseRecords__factory, TokenPriceOracle, TornadoBrowserProvider, TornadoFeeOracle, TornadoRpcSigner, TornadoVoidSigner, TornadoWallet, TovarishClient, addNetwork, addressSchemaType, ajv, base64ToBytes, bigIntReplacer, bnSchemaType, bnToBytes, buffPedersenHash, bufferToBytes, bytes32BNSchemaType, bytes32SchemaType, bytesToBN, bytesToBase64, bytesToHex, calculateScore, calculateSnarkProof, chunk, concatBytes, convertETHToTokenAmount, createDeposit, crypto, customConfig, defaultConfig, defaultUserAgent, deployHasher, depositsEventsSchema, digest, downloadZip, echoEventsSchema, enabledChains, encodedLabelToLabelhash, encryptedNotesSchema, index as factories, fetchData, fetchGetUrlFunc, fetchIp, fromContentHash, gasZipID, gasZipInbounds, gasZipInput, gasZipMinMax, getActiveTokenInstances, getActiveTokens, getConfig, getEventsSchemaValidator, getHttpAgent, getIndexedDB, getInstanceByAddress, getMultiInstances, getNetworkConfig, getPermitSignature, getProvider, getProviderWithNetId, getRelayerEnsSubdomains, getStatusSchema, getSubInfo, getSupportedInstances, getTokenBalances, getTovarishNetworks, getWeightRandom, governanceEventsSchema, hasherBytecode, hexToBytes, initGroth16, isHex, isNode, jobRequestSchema, jobsSchema, labelhash, leBuff2Int, leInt2Buff, loadDBEvents, loadRemoteEvents, makeLabelNodeAndParent, mimc, multiQueryFilter, multicall, numberFormatter, packEncryptedMessage, parseInvoice, parseNote, pedersen, permit2Address, pickWeightedRandomRelayer, populateTransaction, proofSchemaType, proposalState, rBigInt, rHex, relayerRegistryEventsSchema, saveDBEvents, sleep, stakeBurnedEventsSchema, substring, toContentHash, toFixedHex, toFixedLength, tornadoEventsSchema, unpackEncryptedMessage, unzipAsync, validateUrl, withdrawalsEventsSchema, zipAsync }; export { BaseEchoService, BaseEncryptedNotesService, BaseEventsService, BaseGovernanceService, BaseMultiTornadoService, BaseRegistryService, BaseRevenueService, BaseTornadoService, BatchBlockService, BatchEventsService, BatchTransactionService, DBEchoService, DBEncryptedNotesService, DBGovernanceService, DBRegistryService, DBRevenueService, DBTornadoService, Deposit, ENSNameWrapper__factory, ENSRegistry__factory, ENSResolver__factory, ENSUtils, ENS__factory, ERC20__factory, EnsContracts, INDEX_DB_ERROR, IndexedDB, Invoice, MAX_FEE, MAX_TOVARISH_EVENTS, MIN_FEE, MIN_STAKE_BALANCE, MerkleTreeService, Mimc, Multicall__factory, NetId, NoteAccount, OffchainOracle__factory, OvmGasPriceOracle__factory, Pedersen, RelayerClient, ReverseRecords__factory, TokenPriceOracle, TornadoBrowserProvider, TornadoFeeOracle, TornadoRpcSigner, TornadoVoidSigner, TornadoWallet, TovarishClient, addNetwork, addressSchemaType, ajv, base64ToBytes, bigIntReplacer, bnSchemaType, bnToBytes, buffPedersenHash, bufferToBytes, bytes32BNSchemaType, bytes32SchemaType, bytesToBN, bytesToBase64, bytesToHex, calculateScore, calculateSnarkProof, chunk, concatBytes, convertETHToTokenAmount, createDeposit, crypto, customConfig, defaultConfig, defaultUserAgent, deployHasher, depositsEventsSchema, digest, downloadZip, echoEventsSchema, enabledChains, encodedLabelToLabelhash, encryptedNotesSchema, index as factories, fetchData, fetchGetUrlFunc, fetchIp, fromContentHash, gasZipID, gasZipInbounds, gasZipInput, gasZipMinMax, getActiveTokenInstances, getActiveTokens, getConfig, getEventsSchemaValidator, getHttpAgent, getIndexedDB, getInstanceByAddress, getMultiInstances, getNetworkConfig, getPermit2CommitmentsSignature, getPermit2Signature, getPermitCommitmentsSignature, getPermitSignature, getProvider, getProviderWithNetId, getRelayerEnsSubdomains, getStatusSchema, getSubInfo, getSupportedInstances, getTokenBalances, getTovarishNetworks, getWeightRandom, governanceEventsSchema, hasherBytecode, hexToBytes, initGroth16, isHex, isNode, jobRequestSchema, jobsSchema, labelhash, leBuff2Int, leInt2Buff, loadDBEvents, loadRemoteEvents, makeLabelNodeAndParent, mimc, multiQueryFilter, multicall, numberFormatter, packEncryptedMessage, parseInvoice, parseNote, pedersen, permit2Address, pickWeightedRandomRelayer, populateTransaction, proofSchemaType, proposalState, rBigInt, rHex, relayerRegistryEventsSchema, saveDBEvents, sleep, stakeBurnedEventsSchema, substring, toContentHash, toFixedHex, toFixedLength, tornadoEventsSchema, unpackEncryptedMessage, unzipAsync, validateUrl, withdrawalsEventsSchema, zipAsync };

View File

@ -1,4 +1,4 @@
import { MerkleTree, PartialMerkleTree, Element, TreeEdge } from 'fixed-merkle-tree'; import { MerkleTree, PartialMerkleTree, Element, TreeEdge } from '@tornado/fixed-merkle-tree';
import type { Tornado } from '@tornado/contracts'; import type { Tornado } from '@tornado/contracts';
import type { DepositType } from './deposits'; import type { DepositType } from './deposits';
import type { DepositsEvents } from './events'; import type { DepositsEvents } from './events';

19033
dist/merkleTreeWorker.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

2
dist/mimc.d.ts vendored
View File

@ -1,5 +1,5 @@
import { MimcSponge } from 'circomlibjs'; import { MimcSponge } from 'circomlibjs';
import type { Element, HashFunction } from 'fixed-merkle-tree'; import type { Element, HashFunction } from '@tornado/fixed-merkle-tree';
export declare class Mimc { export declare class Mimc {
sponge?: MimcSponge; sponge?: MimcSponge;
hash?: HashFunction<Element>; hash?: HashFunction<Element>;

View File

@ -8,8 +8,6 @@ export declare enum NetId {
POLYGON = 137, POLYGON = 137,
OPTIMISM = 10, OPTIMISM = 10,
ARBITRUM = 42161, ARBITRUM = 42161,
BASE = 8453,
BLAST = 81457,
GNOSIS = 100, GNOSIS = 100,
AVALANCHE = 43114, AVALANCHE = 43114,
SEPOLIA = 11155111 SEPOLIA = 11155111
@ -33,7 +31,6 @@ export interface TornadoInstance {
instanceAddress: { instanceAddress: {
[key: string]: string; [key: string]: string;
}; };
instanceApproval?: boolean;
optionalInstances?: string[]; optionalInstances?: string[];
tokenAddress?: string; tokenAddress?: string;
tokenGasLimit?: number; tokenGasLimit?: number;

176
dist/permit.d.ts vendored
View File

@ -1,5 +1,5 @@
import { ERC20Permit, ERC20Mock, TORN } from '@tornado/contracts'; import { ERC20Permit, ERC20Mock, TORN, PermitTornado } from '@tornado/contracts';
import { Signature, Signer, TypedDataField } from 'ethers'; import { BaseContract, Signature, Signer, TypedDataField } from 'ethers';
export interface PermitValue { export interface PermitValue {
spender: string; spender: string;
value: bigint; value: bigint;
@ -27,85 +27,25 @@ export declare function getPermitSignature({ Token, signer, spender, value, nonc
Token: ERC20Permit | ERC20Mock | TORN; Token: ERC20Permit | ERC20Mock | TORN;
signer?: Signer; signer?: Signer;
}): Promise<Signature>; }): Promise<Signature>;
/** export declare function getPermitCommitmentsSignature({ PermitTornado, Token, signer, denomination, commitments, nonce, }: PermitCommitments & {
export async function getPermitCommitmentsSignature({
PermitTornado,
Token,
signer,
denomination,
commitments,
nonce,
}: PermitCommitments & {
PermitTornado: PermitTornado; PermitTornado: PermitTornado;
Token: ERC20Permit | ERC20Mock | TORN; Token: ERC20Permit | ERC20Mock | TORN;
signer?: Signer; signer?: Signer;
}) { }): Promise<Signature>;
const value = BigInt(commitments.length) * denomination; export declare function getPermit2Signature({ Token, signer, spender, value: amount, nonce, deadline, witness, }: PermitValue & {
const commitmentsHash = solidityPackedKeccak256(['bytes32[]'], [commitments]);
return await getPermitSignature({
Token,
signer,
spender: PermitTornado.target as string,
value,
nonce,
deadline: BigInt(commitmentsHash),
});
}
export async function getPermit2Signature({
Token,
signer,
spender,
value: amount,
nonce,
deadline,
witness,
}: PermitValue & {
Token: BaseContract; Token: BaseContract;
signer?: Signer; signer?: Signer;
witness?: Witness; witness?: Witness;
}) { }): Promise<{
const sigSigner = (signer || Token.runner) as Signer & { address: string }; domain: {
const provider = sigSigner.provider as Provider; name: string;
chainId: bigint;
const domain = { verifyingContract: string;
name: 'Permit2',
chainId: (await provider.getNetwork()).chainId,
verifyingContract: permit2Address,
}; };
types: {
const types: {
[key: string]: TypedDataField[]; [key: string]: TypedDataField[];
} = !witness };
? { values: {
PermitTransferFrom: [
{ name: 'permitted', type: 'TokenPermissions' },
{ name: 'spender', type: 'address' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
],
TokenPermissions: [
{ name: 'token', type: 'address' },
{ name: 'amount', type: 'uint256' },
],
}
: {
PermitWitnessTransferFrom: [
{ name: 'permitted', type: 'TokenPermissions' },
{ name: 'spender', type: 'address' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
{ name: 'witness', type: witness.witnessTypeName },
],
TokenPermissions: [
{ name: 'token', type: 'address' },
{ name: 'amount', type: 'uint256' },
],
...witness.witnessType,
};
const values: {
permitted: { permitted: {
token: string; token: string;
amount: bigint; amount: bigint;
@ -113,72 +53,34 @@ export async function getPermit2Signature({
spender: string; spender: string;
nonce: bigint; nonce: bigint;
deadline: bigint; deadline: bigint;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
witness?: any; witness?: any;
} = {
permitted: {
token: Token.target as string,
amount,
},
spender,
// Sorted nonce are not required for Permit2
nonce: nonce || rBigInt(16),
deadline: deadline || MaxUint256,
}; };
hash: string;
if (witness) { signature: Signature;
values.witness = witness.witness; }>;
} export declare function getPermit2CommitmentsSignature({ PermitTornado, Token, signer, denomination, commitments, nonce, deadline, }: PermitCommitments & {
const hash = new TypedDataEncoder(types).hash(values);
const signature = Signature.from(await sigSigner.signTypedData(domain, types, values));
return {
domain,
types,
values,
hash,
signature,
};
}
export async function getPermit2CommitmentsSignature({
PermitTornado,
Token,
signer,
denomination,
commitments,
nonce,
deadline,
}: PermitCommitments & {
PermitTornado: PermitTornado; PermitTornado: PermitTornado;
Token: BaseContract; Token: BaseContract;
signer?: Signer; signer?: Signer;
}) { }): Promise<{
const value = BigInt(commitments.length) * denomination; domain: {
const commitmentsHash = solidityPackedKeccak256(['bytes32[]'], [commitments]); name: string;
chainId: bigint;
return await getPermit2Signature({ verifyingContract: string;
Token, };
signer, types: {
spender: PermitTornado.target as string, [key: string]: TypedDataField[];
value, };
nonce, values: {
deadline, permitted: {
witness: { token: string;
witnessTypeName: 'PermitCommitments', amount: bigint;
witnessType: { };
PermitCommitments: [ spender: string;
{ name: 'instance', type: 'address' }, nonce: bigint;
{ name: 'commitmentsHash', type: 'bytes32' }, deadline: bigint;
], witness?: any;
}, };
witness: { hash: string;
instance: PermitTornado.target, signature: Signature;
commitmentsHash, }>;
},
},
});
}
**/

4
dist/providers.d.ts vendored
View File

@ -43,7 +43,6 @@ export interface TornadoWalletOptions {
gasLimitBump?: number; gasLimitBump?: number;
gasFailover?: boolean; gasFailover?: boolean;
bumpNonce?: boolean; bumpNonce?: boolean;
readonlyProvider?: Provider;
} }
export declare class TornadoWallet extends Wallet { export declare class TornadoWallet extends Wallet {
nonce?: number; nonce?: number;
@ -70,8 +69,7 @@ export declare class TornadoRpcSigner extends JsonRpcSigner {
gasLimitBump: number; gasLimitBump: number;
gasFailover: boolean; gasFailover: boolean;
bumpNonce: boolean; bumpNonce: boolean;
readonlyProvider?: Provider; constructor(provider: JsonRpcApiProvider, address: string, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }?: TornadoWalletOptions);
constructor(provider: JsonRpcApiProvider, address: string, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce, readonlyProvider }?: TornadoWalletOptions);
sendUncheckedTransaction(tx: TransactionRequest): Promise<string>; sendUncheckedTransaction(tx: TransactionRequest): Promise<string>;
} }
export type connectWalletFunc = (...args: any[]) => Promise<void>; export type connectWalletFunc = (...args: any[]) => Promise<void>;

42216
dist/tornado.umd.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
dist/websnark.d.ts vendored
View File

@ -1,4 +1,4 @@
import type { Element } from 'fixed-merkle-tree'; import type { Element } from '@tornado/fixed-merkle-tree';
export interface snarkInputs { export interface snarkInputs {
root: Element; root: Element;
nullifierHex: string; nullifierHex: string;

View File

@ -13,10 +13,7 @@
"lint": "eslint src/**/*.ts test/**/*.ts --ext .ts --ignore-pattern src/typechain", "lint": "eslint src/**/*.ts test/**/*.ts --ext .ts --ignore-pattern src/typechain",
"build:node": "rollup -c", "build:node": "rollup -c",
"build:web": "webpack", "build:web": "webpack",
"build:hash": "ts-node scripts/hash.ts", "build": "yarn types && yarn build:node && yarn build:web",
"build": "yarn types && yarn build:node && yarn build:web && yarn build:hash",
"ipfs:build": "docker build -t tornado-core .",
"ipfs:hash": "docker container run --rm -it --entrypoint cat tornado-core /app/dist/hashes.json",
"test": "nyc mocha --require ts-node/register --require source-map-support/register --recursive 'test/**/*.ts' --timeout '300000'" "test": "nyc mocha --require ts-node/register --require source-map-support/register --recursive 'test/**/*.ts' --timeout '300000'"
}, },
"author": "", "author": "",
@ -37,7 +34,10 @@
"dependencies": { "dependencies": {
"@ensdomains/content-hash": "2.5.7", "@ensdomains/content-hash": "2.5.7",
"@metamask/eth-sig-util": "^8.0.0", "@metamask/eth-sig-util": "^8.0.0",
"@tornado/contracts": "git+https://git.tornado.ws/tornadocontrib/tornado-contracts.git#093ae2210e1f1b016b756b4db200c4a1b3308408", "@tornado/contracts": "git+https://git.tornado.ws/tornadocontrib/tornado-contracts.git#1b1d707878c16a3dc60d295299d4f0e7ce6ba831",
"@tornado/fixed-merkle-tree": "^0.7.3",
"@tornado/snarkjs": "^0.1.20",
"@tornado/websnark": "^0.0.4",
"ajv": "^8.17.1", "ajv": "^8.17.1",
"bn.js": "^5.2.1", "bn.js": "^5.2.1",
"circomlibjs": "0.1.7", "circomlibjs": "0.1.7",
@ -45,10 +45,7 @@
"ethers": "^6.13.4", "ethers": "^6.13.4",
"ffjavascript": "0.2.48", "ffjavascript": "0.2.48",
"fflate": "^0.8.2", "fflate": "^0.8.2",
"fixed-merkle-tree": "0.7.3", "idb": "^8.0.0"
"idb": "^8.0.0",
"snarkjs": "git+https://github.com/tornadocontrib/snarkjs.git#2c964b3fe6019e057acab04cc17705d1f7fdaf9a",
"websnark": "git+https://github.com/tornadocontrib/websnark.git#f0ddbf34b3045cac9e6d3e4d977bf3b439869fae"
}, },
"devDependencies": { "devDependencies": {
"@nomicfoundation/hardhat-chai-matchers": "^2.0.7", "@nomicfoundation/hardhat-chai-matchers": "^2.0.7",
@ -72,7 +69,6 @@
"@types/node-fetch": "^2.6.11", "@types/node-fetch": "^2.6.11",
"@typescript-eslint/eslint-plugin": "^8.11.0", "@typescript-eslint/eslint-plugin": "^8.11.0",
"@typescript-eslint/parser": "^8.11.0", "@typescript-eslint/parser": "^8.11.0",
"chai": "4.5.0",
"esbuild-loader": "^4.2.2", "esbuild-loader": "^4.2.2",
"eslint": "8.57.0", "eslint": "8.57.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
@ -100,8 +96,6 @@
"strip-ansi": "6.0.1", "strip-ansi": "6.0.1",
"@adraffy/ens-normalize": "1.10.1", "@adraffy/ens-normalize": "1.10.1",
"@noble/curves": "1.2.0", "@noble/curves": "1.2.0",
"@noble/hashes": "1.3.2", "@noble/hashes": "1.3.2"
"big-integer": "1.6.52",
"ffjavascript": "0.2.48"
} }
} }

View File

@ -12,8 +12,8 @@ const external = Object.keys(pkgJson.dependencies).concat(
'http-proxy-agent', 'http-proxy-agent',
'https-proxy-agent', 'https-proxy-agent',
'socks-proxy-agent', 'socks-proxy-agent',
'websnark/src/utils', '@tornado/websnark/src/utils',
'websnark/src/groth16', '@tornado/websnark/src/groth16',
] ]
); );

View File

@ -1,36 +0,0 @@
import path from 'path'
import { readFile, readdir, writeFile } from 'fs/promises';
import { bytesToBase64, digest } from '../src';
async function content(file: string) {
const content = new Uint8Array(await readFile(file));
const hash = 'sha384-' + bytesToBase64(await digest(content));
return hash;
}
async function hash() {
const staticFiles = await readdir('dist');
const hashes = {} as {
[key: string]: string;
};
for (const filePath of staticFiles) {
const file = path.join('dist', filePath).replaceAll(path.sep, path.posix.sep);
if (!['.js', '.mjs'].includes(path.extname(file))) {
continue;
}
const hash = await content(file);
hashes[file] = hash;
}
await writeFile('dist/hashes.json', JSON.stringify(hashes, null, 2));
console.log('hashes', hashes);
}
hash();

View File

@ -22,7 +22,7 @@ import {
Tornado__factory, Tornado__factory,
} from '@tornado/contracts'; } from '@tornado/contracts';
import type { MerkleTree } from 'fixed-merkle-tree'; import type { MerkleTree } from '@tornado/fixed-merkle-tree';
import { import {
BatchEventsService, BatchEventsService,
BatchBlockService, BatchBlockService,
@ -36,7 +36,7 @@ import { enabledChains, type NetIdType, type SubdomainMap } from '../networkConf
import { RelayerParams, MIN_STAKE_BALANCE } from '../relayerClient'; import { RelayerParams, MIN_STAKE_BALANCE } from '../relayerClient';
import type { TovarishClient } from '../tovarishClient'; import type { TovarishClient } from '../tovarishClient';
import type { ERC20, ReverseRecords } from '../typechain'; import type { ReverseRecords } from '../typechain';
import type { MerkleTreeService } from '../merkleTree'; import type { MerkleTreeService } from '../merkleTree';
import type { DepositType } from '../deposits'; import type { DepositType } from '../deposits';
import type { import type {
@ -60,7 +60,6 @@ import type {
StakeBurnedEvents, StakeBurnedEvents,
MultiDepositsEvents, MultiDepositsEvents,
MultiWithdrawalsEvents, MultiWithdrawalsEvents,
TransferEvents,
} from './types'; } from './types';
export interface BaseEventsServiceConstructor { export interface BaseEventsServiceConstructor {
@ -157,9 +156,6 @@ export class BaseEventsService<EventType extends MinimalEvents> {
}; };
} }
/**
* This may not return in sorted events when called from browser, make sure to sort it again when directly called
*/
async getSavedEvents(): Promise<BaseEvents<EventType> | CachedEvents<EventType>> { async getSavedEvents(): Promise<BaseEvents<EventType> | CachedEvents<EventType>> {
let dbEvents = await this.getEventsFromDB(); let dbEvents = await this.getEventsFromDB();
@ -617,9 +613,9 @@ export class BaseMultiTornadoService extends BaseEventsService<MultiDepositsEven
} }
return acc; return acc;
}, },
{ {} as {
depositEvents: [] as MultiDepositsEvents[], depositEvents: MultiDepositsEvents[];
withdrawalEvents: [] as MultiWithdrawalsEvents[], withdrawalEvents: MultiWithdrawalsEvents[];
}, },
); );
@ -996,12 +992,7 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
} }
async getVotes(proposalId: number): Promise<GovernanceVotes[]> { async getVotes(proposalId: number): Promise<GovernanceVotes[]> {
const events = (await this.getSavedEvents()).events.sort((a, b) => { const { events } = await this.getSavedEvents();
if (a.blockNumber === b.blockNumber) {
return a.logIndex - b.logIndex;
}
return a.blockNumber - b.blockNumber;
});
const votedEvents = events.filter( const votedEvents = events.filter(
(e) => e.event === 'Voted' && (e as GovernanceVotedEvents).proposalId === proposalId, (e) => e.event === 'Voted' && (e as GovernanceVotedEvents).proposalId === proposalId,
@ -1039,12 +1030,7 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
} }
async getDelegatedBalance(ethAccount: string) { async getDelegatedBalance(ethAccount: string) {
const events = (await this.getSavedEvents()).events.sort((a, b) => { const { events } = await this.getSavedEvents();
if (a.blockNumber === b.blockNumber) {
return a.logIndex - b.logIndex;
}
return a.blockNumber - b.blockNumber;
});
const delegatedAccs = events const delegatedAccs = events
.filter((e) => e.event === 'Delegated' && (e as GovernanceDelegatedEvents).delegateTo === ethAccount) .filter((e) => e.event === 'Delegated' && (e as GovernanceDelegatedEvents).delegateTo === ethAccount)
@ -1140,13 +1126,6 @@ const staticRelayers: CachedRelayerInfo[] = [
tovarishHost: 'tornadowithdraw.com', tovarishHost: 'tornadowithdraw.com',
tovarishNetworks: enabledChains, tovarishNetworks: enabledChains,
}, },
{
ensName: 'rpc.tornadowithdraw.eth',
relayerAddress: '0xFF787B7A5cd8a88508361E3B7bcE791Aa2796526',
hostnames: {},
tovarishHost: 'tornadocash-rpc.com',
tovarishNetworks: enabledChains,
},
]; ];
export interface CachedRelayers { export interface CachedRelayers {
@ -1505,38 +1484,3 @@ export class BaseRevenueService extends BaseEventsService<StakeBurnedEvents> {
}); });
} }
} }
export interface BaseTransferServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
Token: ERC20;
}
export class BaseTransferService extends BaseEventsService<TransferEvents> {
constructor(serviceConstructor: BaseTransferServiceConstructor) {
super({
...serviceConstructor,
contract: serviceConstructor.Token,
type: 'Transfer',
});
}
async formatEvents(events: EventLog[]) {
return events
.map(({ blockNumber, index: logIndex, transactionHash, args }) => {
const { from, to, value } = args;
const eventObjects = {
blockNumber,
logIndex,
transactionHash,
};
return {
...eventObjects,
from,
to,
value,
};
})
.filter((e) => e) as TransferEvents[];
}
}

View File

@ -17,8 +17,6 @@ import {
BaseRevenueService, BaseRevenueService,
BaseRevenueServiceConstructor, BaseRevenueServiceConstructor,
CachedRelayers, CachedRelayers,
BaseMultiTornadoService,
BaseMultiTornadoServiceConstructor,
} from './base'; } from './base';
import { import {
@ -32,23 +30,21 @@ import {
AllGovernanceEvents, AllGovernanceEvents,
AllRelayerRegistryEvents, AllRelayerRegistryEvents,
StakeBurnedEvents, StakeBurnedEvents,
MultiDepositsEvents,
MultiWithdrawalsEvents,
} from './types'; } from './types';
export async function saveDBEvents<T extends MinimalEvents>({ export async function saveDBEvents<T extends MinimalEvents>({
idb, idb,
instanceName, instanceName,
newEvents, events,
lastBlock, lastBlock,
}: { }: {
idb: IndexedDB; idb: IndexedDB;
instanceName: string; instanceName: string;
newEvents: T[]; events: T[];
lastBlock: number; lastBlock: number;
}) { }) {
try { try {
const formattedEvents = newEvents.map((e) => { const formattedEvents = events.map((e) => {
return { return {
eid: `${e.transactionHash}_${e.logIndex}`, eid: `${e.transactionHash}_${e.logIndex}`,
...e, ...e,
@ -196,63 +192,11 @@ export class DBTornadoService extends BaseTornadoService {
}); });
} }
async saveEvents({ async saveEvents({ events, lastBlock }: BaseEvents<DepositsEvents | WithdrawalsEvents>) {
newEvents,
lastBlock,
}: BaseEvents<DepositsEvents | WithdrawalsEvents> & { newEvents: (DepositsEvents | WithdrawalsEvents)[] }) {
await saveDBEvents<DepositsEvents | WithdrawalsEvents>({ await saveDBEvents<DepositsEvents | WithdrawalsEvents>({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock,
});
}
}
export interface DBMultiTornadoServiceConstructor extends BaseMultiTornadoServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export class DBMultiTornadoService extends BaseMultiTornadoService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
constructor(params: DBMultiTornadoServiceConstructor) {
super(params);
this.staticUrl = params.staticUrl;
this.idb = params.idb;
}
async getEventsFromDB() {
return await loadDBEvents<MultiDepositsEvents | MultiWithdrawalsEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
});
}
async getEventsFromCache() {
return await loadRemoteEvents<MultiDepositsEvents | MultiWithdrawalsEvents>({
staticUrl: this.staticUrl,
instanceName: this.getInstanceName(),
deployedBlock: this.deployedBlock,
zipDigest: this.zipDigest,
});
}
async saveEvents({
newEvents,
lastBlock,
}: BaseEvents<MultiDepositsEvents | MultiWithdrawalsEvents> & {
newEvents: (MultiDepositsEvents | MultiWithdrawalsEvents)[];
}) {
await saveDBEvents<MultiDepositsEvents | MultiWithdrawalsEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
newEvents,
lastBlock, lastBlock,
}); });
} }
@ -292,11 +236,11 @@ export class DBEchoService extends BaseEchoService {
}); });
} }
async saveEvents({ newEvents, lastBlock }: BaseEvents<EchoEvents> & { newEvents: EchoEvents[] }) { async saveEvents({ events, lastBlock }: BaseEvents<EchoEvents>) {
await saveDBEvents<EchoEvents>({ await saveDBEvents<EchoEvents>({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock, lastBlock,
}); });
} }
@ -336,14 +280,11 @@ export class DBEncryptedNotesService extends BaseEncryptedNotesService {
}); });
} }
async saveEvents({ async saveEvents({ events, lastBlock }: BaseEvents<EncryptedNotesEvents>) {
newEvents,
lastBlock,
}: BaseEvents<EncryptedNotesEvents> & { newEvents: EncryptedNotesEvents[] }) {
await saveDBEvents<EncryptedNotesEvents>({ await saveDBEvents<EncryptedNotesEvents>({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock, lastBlock,
}); });
} }
@ -383,11 +324,11 @@ export class DBGovernanceService extends BaseGovernanceService {
}); });
} }
async saveEvents({ newEvents, lastBlock }: BaseEvents<AllGovernanceEvents> & { newEvents: AllGovernanceEvents[] }) { async saveEvents({ events, lastBlock }: BaseEvents<AllGovernanceEvents>) {
await saveDBEvents<AllGovernanceEvents>({ await saveDBEvents<AllGovernanceEvents>({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock, lastBlock,
}); });
} }
@ -428,14 +369,11 @@ export class DBRegistryService extends BaseRegistryService {
}); });
} }
async saveEvents({ async saveEvents({ events, lastBlock }: BaseEvents<AllRelayerRegistryEvents>) {
newEvents,
lastBlock,
}: BaseEvents<AllRelayerRegistryEvents> & { newEvents: AllRelayerRegistryEvents[] }) {
await saveDBEvents<AllRelayerRegistryEvents>({ await saveDBEvents<AllRelayerRegistryEvents>({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock, lastBlock,
}); });
} }
@ -548,11 +486,11 @@ export class DBRevenueService extends BaseRevenueService {
}); });
} }
async saveEvents({ newEvents, lastBlock }: BaseEvents<StakeBurnedEvents> & { newEvents: StakeBurnedEvents[] }) { async saveEvents({ events, lastBlock }: BaseEvents<StakeBurnedEvents>) {
await saveDBEvents<StakeBurnedEvents>({ await saveDBEvents<StakeBurnedEvents>({
idb: this.idb, idb: this.idb,
instanceName: this.getInstanceName(), instanceName: this.getInstanceName(),
newEvents, events,
lastBlock, lastBlock,
}); });
} }

View File

@ -132,9 +132,3 @@ export interface EchoEvents extends MinimalEvents {
export interface EncryptedNotesEvents extends MinimalEvents { export interface EncryptedNotesEvents extends MinimalEvents {
encryptedNote: string; encryptedNote: string;
} }
export interface TransferEvents extends MinimalEvents {
from: string;
to: string;
value: bigint;
}

View File

@ -55,7 +55,7 @@ export class TornadoFeeOracle {
* (A single block can bump 12.5% of fees, see the methodology https://hackmd.io/@tvanepps/1559-wallets) * (A single block can bump 12.5% of fees, see the methodology https://hackmd.io/@tvanepps/1559-wallets)
* (Still it is recommended to use 100% premium for sending transactions to prevent stucking it) * (Still it is recommended to use 100% premium for sending transactions to prevent stucking it)
*/ */
async gasPrice(premium?: number) { async gasPrice() {
const [block, getGasPrice, getPriorityFee] = await Promise.all([ const [block, getGasPrice, getPriorityFee] = await Promise.all([
this.provider.getBlock('latest'), this.provider.getBlock('latest'),
(async () => { (async () => {
@ -74,9 +74,7 @@ export class TornadoFeeOracle {
})(), })(),
]); ]);
return block?.baseFeePerGas return block?.baseFeePerGas ? (block.baseFeePerGas * BigInt(15)) / BigInt(10) + getPriorityFee : getGasPrice;
? (block.baseFeePerGas * BigInt(10000 * (100 + (premium || 50)))) / BigInt(10000 * 100) + getPriorityFee
: getGasPrice;
} }
/** /**
@ -84,7 +82,7 @@ export class TornadoFeeOracle {
* *
* This is required since relayers would pay the full transaction fees for users * This is required since relayers would pay the full transaction fees for users
*/ */
async fetchL1OptimismFee(tx?: TransactionLike): Promise<bigint> { fetchL1OptimismFee(tx?: TransactionLike): Promise<bigint> {
if (!this.ovmGasPriceOracle) { if (!this.ovmGasPriceOracle) {
return new Promise((resolve) => resolve(BigInt(0))); return new Promise((resolve) => resolve(BigInt(0)));
} }
@ -102,9 +100,7 @@ export class TornadoFeeOracle {
}; };
} }
return ( return this.ovmGasPriceOracle.getL1Fee.staticCall(Transaction.from(tx).unsignedSerialized);
((await this.ovmGasPriceOracle.getL1Fee.staticCall(Transaction.from(tx).unsignedSerialized)) * 12n) / 10n
);
} }
/** /**

View File

@ -8,8 +8,6 @@ export const gasZipInbounds: { [key in NetIdType]: string } = {
[NetId.POLYGON]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604', [NetId.POLYGON]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.OPTIMISM]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604', [NetId.OPTIMISM]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.ARBITRUM]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604', [NetId.ARBITRUM]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.BASE]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.BLAST]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.GNOSIS]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604', [NetId.GNOSIS]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.AVALANCHE]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604', [NetId.AVALANCHE]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
}; };
@ -21,8 +19,6 @@ export const gasZipID: { [key in NetIdType]: number } = {
[NetId.POLYGON]: 17, [NetId.POLYGON]: 17,
[NetId.OPTIMISM]: 55, [NetId.OPTIMISM]: 55,
[NetId.ARBITRUM]: 57, [NetId.ARBITRUM]: 57,
[NetId.BASE]: 54,
[NetId.BLAST]: 96,
[NetId.GNOSIS]: 16, [NetId.GNOSIS]: 16,
[NetId.AVALANCHE]: 15, [NetId.AVALANCHE]: 15,
[NetId.SEPOLIA]: 102, [NetId.SEPOLIA]: 102,

View File

@ -55,7 +55,7 @@ export class IndexedDB {
}; };
this.dbName = dbName; this.dbName = dbName;
this.dbVersion = 36; this.dbVersion = 35;
} }
async initDB() { async initDB() {
@ -324,17 +324,16 @@ export async function getIndexedDB(netId?: NetIdType) {
const minimalIndexes = [ const minimalIndexes = [
{ {
name: 'eid', name: 'blockNumber',
unique: true, unique: false,
},
{
name: 'transactionHash',
unique: false,
}, },
]; ];
const defaultState = [ const defaultState = [
{
name: `tornado_${netId}`,
keyPath: 'eid',
indexes: [...minimalIndexes],
},
{ {
name: `echo_${netId}`, name: `echo_${netId}`,
keyPath: 'eid', keyPath: 'eid',
@ -363,7 +362,9 @@ export async function getIndexedDB(netId?: NetIdType) {
}, },
]; ];
const { tokens, nativeCurrency, registryContract, governanceContract } = getConfig(netId); const config = getConfig(netId);
const { tokens, nativeCurrency, registryContract, governanceContract } = config;
const stores = [...defaultState]; const stores = [...defaultState];

View File

@ -1,5 +1,5 @@
import { Worker as NodeWorker } from 'worker_threads'; import { Worker as NodeWorker } from 'worker_threads';
import { MerkleTree, PartialMerkleTree, Element, TreeEdge } from 'fixed-merkle-tree'; import { MerkleTree, PartialMerkleTree, Element, TreeEdge } from '@tornado/fixed-merkle-tree';
import type { Tornado } from '@tornado/contracts'; import type { Tornado } from '@tornado/contracts';
import { isNode, toFixedHex } from './utils'; import { isNode, toFixedHex } from './utils';
import { mimc } from './mimc'; import { mimc } from './mimc';

View File

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import workerThreads from 'worker_threads'; import workerThreads from 'worker_threads';
import { MerkleTree, Element, TreeEdge, PartialMerkleTree } from 'fixed-merkle-tree'; import { MerkleTree, Element, TreeEdge, PartialMerkleTree } from '@tornado/fixed-merkle-tree';
import { mimc } from './mimc'; import { mimc } from './mimc';
import { isNode } from './utils'; import { isNode } from './utils';

View File

@ -1,5 +1,5 @@
import { MimcSponge, buildMimcSponge } from 'circomlibjs'; import { MimcSponge, buildMimcSponge } from 'circomlibjs';
import type { Element, HashFunction } from 'fixed-merkle-tree'; import type { Element, HashFunction } from '@tornado/fixed-merkle-tree';
export class Mimc { export class Mimc {
sponge?: MimcSponge; sponge?: MimcSponge;

View File

@ -9,8 +9,6 @@ export enum NetId {
POLYGON = 137, POLYGON = 137,
OPTIMISM = 10, OPTIMISM = 10,
ARBITRUM = 42161, ARBITRUM = 42161,
BASE = 8453,
BLAST = 81457,
GNOSIS = 100, GNOSIS = 100,
AVALANCHE = 43114, AVALANCHE = 43114,
SEPOLIA = 11155111, SEPOLIA = 11155111,
@ -40,7 +38,6 @@ export interface TornadoInstance {
instanceAddress: { instanceAddress: {
[key: string]: string; [key: string]: string;
}; };
instanceApproval?: boolean;
optionalInstances?: string[]; optionalInstances?: string[];
tokenAddress?: string; tokenAddress?: string;
tokenGasLimit?: number; tokenGasLimit?: number;
@ -135,10 +132,6 @@ export const defaultConfig: networkConfig = {
name: 'MEV Blocker', name: 'MEV Blocker',
url: 'https://rpc.mevblocker.io', url: 'https://rpc.mevblocker.io',
}, },
tornadoRpc: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com',
},
keydonix: { keydonix: {
name: 'Horswap ( Keydonix )', name: 'Horswap ( Keydonix )',
url: 'https://ethereum.keydonix.com/v1/mainnet', url: 'https://ethereum.keydonix.com/v1/mainnet',
@ -258,10 +251,10 @@ export const defaultConfig: networkConfig = {
[NetId.BSC]: { [NetId.BSC]: {
rpcCallRetryAttempt: 15, rpcCallRetryAttempt: 15,
gasPrices: { gasPrices: {
instant: 3, instant: 5,
fast: 1, fast: 5,
standard: 1, standard: 5,
low: 1, low: 5,
}, },
nativeCurrency: 'bnb', nativeCurrency: 'bnb',
currencyName: 'BNB', currencyName: 'BNB',
@ -286,10 +279,6 @@ export const defaultConfig: networkConfig = {
name: 'BNB Chain 2', name: 'BNB Chain 2',
url: 'https://bsc-dataseed1.ninicoin.io', url: 'https://bsc-dataseed1.ninicoin.io',
}, },
tornadoRpc: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com/bsc',
},
nodereal: { nodereal: {
name: 'NodeReal', name: 'NodeReal',
url: 'https://binance.nodereal.io', url: 'https://binance.nodereal.io',
@ -314,38 +303,9 @@ export const defaultConfig: networkConfig = {
symbol: 'BNB', symbol: 'BNB',
decimals: 18, decimals: 18,
}, },
usdt: {
instanceAddress: {
'10': '0x261fB4f84bb0BdEe7E035B6a8a08e5c35AdacdDD',
'100': '0x3957861d4897d883C9b944C0b4E22bBd0DDE6e21',
'1000': '0x6D180403AdFb39F70983eB51A033C5e52eb9BB69',
'10000': '0x3722662D8AaB07B216B14C02eF0ee940d14A4200',
},
instanceApproval: true,
tokenAddress: '0x55d398326f99059fF775485246999027B3197955',
tokenGasLimit: 70_000,
symbol: 'USDT',
decimals: 18,
gasLimit: 700_000,
},
btcb: {
instanceAddress: {
'0.0001': '0x736dABbFc8101Ae75287104eCcf67e45D7369Ae1',
'0.001': '0x82c7Ce6f1F158cEC5536d591a2BC19864b3CA823',
'0.01': '0x8284c96679037d8081E498d8F767cA5a140BFAAf',
'0.1': '0x2bcD128Ce23ee30Ee945E613ff129c4DE1102C79',
},
instanceApproval: true,
tokenAddress: '0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c',
tokenGasLimit: 70_000,
symbol: 'BTCB',
decimals: 18,
gasLimit: 700_000,
},
}, },
optionalTokens: ['usdt', 'btcb'],
relayerEnsSubdomain: 'bsc-tornado', relayerEnsSubdomain: 'bsc-tornado',
pollInterval: 3, pollInterval: 10,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 8159269, NOTE_ACCOUNT_BLOCK: 8159269,
ENCRYPTED_NOTES_BLOCK: 8159269, ENCRYPTED_NOTES_BLOCK: 8159269,
@ -354,9 +314,9 @@ export const defaultConfig: networkConfig = {
[NetId.POLYGON]: { [NetId.POLYGON]: {
rpcCallRetryAttempt: 15, rpcCallRetryAttempt: 15,
gasPrices: { gasPrices: {
instant: 60, instant: 100,
fast: 30, fast: 75,
standard: 30, standard: 50,
low: 30, low: 30,
}, },
nativeCurrency: 'matic', nativeCurrency: 'matic',
@ -396,7 +356,7 @@ export const defaultConfig: networkConfig = {
}, },
}, },
relayerEnsSubdomain: 'polygon-tornado', relayerEnsSubdomain: 'polygon-tornado',
pollInterval: 2, pollInterval: 10,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 16257996, NOTE_ACCOUNT_BLOCK: 16257996,
ENCRYPTED_NOTES_BLOCK: 16257996, ENCRYPTED_NOTES_BLOCK: 16257996,
@ -438,20 +398,17 @@ export const defaultConfig: networkConfig = {
tokens: { tokens: {
eth: { eth: {
instanceAddress: { instanceAddress: {
'0.001': '0x82859DC3697062c16422E9b5e8Ba1B6a6EC72c76',
'0.01': '0xA287c40411685438750a247Ca67488DEBe56EE32',
'0.1': '0x84443CFd09A48AF6eF360C6976C5392aC5023a1F', '0.1': '0x84443CFd09A48AF6eF360C6976C5392aC5023a1F',
'1': '0xd47438C816c9E7f2E2888E060936a499Af9582b3', '1': '0xd47438C816c9E7f2E2888E060936a499Af9582b3',
'10': '0x330bdFADE01eE9bF63C209Ee33102DD334618e0a', '10': '0x330bdFADE01eE9bF63C209Ee33102DD334618e0a',
'100': '0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD', '100': '0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD',
}, },
optionalInstances: ['0.001', '0.01'],
symbol: 'ETH', symbol: 'ETH',
decimals: 18, decimals: 18,
}, },
}, },
relayerEnsSubdomain: 'optimism-tornado', relayerEnsSubdomain: 'optimism-tornado',
pollInterval: 2, pollInterval: 15,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 2243694, NOTE_ACCOUNT_BLOCK: 2243694,
ENCRYPTED_NOTES_BLOCK: 2243694, ENCRYPTED_NOTES_BLOCK: 2243694,
@ -460,10 +417,10 @@ export const defaultConfig: networkConfig = {
[NetId.ARBITRUM]: { [NetId.ARBITRUM]: {
rpcCallRetryAttempt: 15, rpcCallRetryAttempt: 15,
gasPrices: { gasPrices: {
instant: 0.02, instant: 4,
fast: 0.02, fast: 3,
standard: 0.02, standard: 2.52,
low: 0.02, low: 2.29,
}, },
nativeCurrency: 'eth', nativeCurrency: 'eth',
currencyName: 'ETH', currencyName: 'ETH',
@ -484,10 +441,6 @@ export const defaultConfig: networkConfig = {
name: 'Arbitrum', name: 'Arbitrum',
url: 'https://arb1.arbitrum.io/rpc', url: 'https://arb1.arbitrum.io/rpc',
}, },
tornadoRpc: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com/arbitrum',
},
stackup: { stackup: {
name: 'Stackup', name: 'Stackup',
url: 'https://public.stackup.sh/api/v1/node/arbitrum-one', url: 'https://public.stackup.sh/api/v1/node/arbitrum-one',
@ -500,166 +453,22 @@ export const defaultConfig: networkConfig = {
tokens: { tokens: {
eth: { eth: {
instanceAddress: { instanceAddress: {
'0.001': '0x82859DC3697062c16422E9b5e8Ba1B6a6EC72c76',
'0.01': '0xA287c40411685438750a247Ca67488DEBe56EE32',
'0.1': '0x84443CFd09A48AF6eF360C6976C5392aC5023a1F', '0.1': '0x84443CFd09A48AF6eF360C6976C5392aC5023a1F',
'1': '0xd47438C816c9E7f2E2888E060936a499Af9582b3', '1': '0xd47438C816c9E7f2E2888E060936a499Af9582b3',
'10': '0x330bdFADE01eE9bF63C209Ee33102DD334618e0a', '10': '0x330bdFADE01eE9bF63C209Ee33102DD334618e0a',
'100': '0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD', '100': '0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD',
}, },
optionalInstances: ['0.001', '0.01'],
symbol: 'ETH', symbol: 'ETH',
decimals: 18, decimals: 18,
}, },
}, },
relayerEnsSubdomain: 'arbitrum-tornado', relayerEnsSubdomain: 'arbitrum-tornado',
pollInterval: 2, pollInterval: 15,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 3430605, NOTE_ACCOUNT_BLOCK: 3430605,
ENCRYPTED_NOTES_BLOCK: 3430605, ENCRYPTED_NOTES_BLOCK: 3430605,
}, },
}, },
[NetId.BASE]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 0.1,
fast: 0.06,
standard: 0.05,
low: 0.02,
},
nativeCurrency: 'eth',
currencyName: 'ETH',
explorerUrl: 'https://basescan.org',
merkleTreeHeight: 20,
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Base',
deployedBlock: 23149794,
stablecoin: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
offchainOracleContract: '0x00000000000D6FFc74A8feb35aF5827bf57f6786',
ovmGasPriceOracleContract: '0x420000000000000000000000000000000000000F',
tornadoSubgraph: 'tornadocash/base-tornado-subgraph',
subgraphs: {},
rpcUrls: {
Base: {
name: 'Base',
url: 'https://mainnet.base.org',
},
stackup: {
name: 'Stackup',
url: 'https://public.stackup.sh/api/v1/node/base-mainnet',
},
oneRpc: {
name: '1RPC',
url: 'https://1rpc.io/base',
},
},
tokens: {
eth: {
instanceAddress: {
'0.001': '0x82859DC3697062c16422E9b5e8Ba1B6a6EC72c76',
'0.01': '0xA287c40411685438750a247Ca67488DEBe56EE32',
'0.1': '0x84443CFd09A48AF6eF360C6976C5392aC5023a1F',
'1': '0xd47438C816c9E7f2E2888E060936a499Af9582b3',
'10': '0x330bdFADE01eE9bF63C209Ee33102DD334618e0a',
'100': '0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD',
},
symbol: 'ETH',
decimals: 18,
},
dai: {
instanceAddress: {
'10': '0x70CC374aE7D1549a4666b7172B78dDCF672B74f7',
'100': '0xD063894588177B8362Dda6C0A7EF09BF6fDF851c',
'1000': '0xa7513fdfF61fc83a9C5c08CE31266e6dd400C54E',
'10000': '0x8f05eDE57098D843F30bE74AC25c292F87b7f775',
'100000': '0xeB7fc86c32e9a5E9DD2a0a78C091b8b625cbee24',
},
instanceApproval: true,
tokenAddress: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb',
tokenGasLimit: 70_000,
symbol: 'DAI',
decimals: 18,
gasLimit: 700_000,
},
tbtc: {
instanceAddress: {
'0.0001': '0x5465800D7Be34dAe2c1572d2227De94dE93B4432',
'0.001': '0xf2d3404c03C8cC0b120bd6E8edD6F69226F03c6d',
'0.01': '0x4261d5209A285410DEa8173B6FE1A0e7BCf20f7c',
'0.1': '0x9FB147F49bFE17D19789547187EAE2406590b217',
'1': '0x2A8515F39716B0C160a3eB32D24E4cbeB76932d2',
},
instanceApproval: true,
tokenAddress: '0x236aa50979D5f3De3Bd1Eeb40E81137F22ab794b',
tokenGasLimit: 70_000,
symbol: 'tBTC',
decimals: 18,
gasLimit: 700_000,
},
},
relayerEnsSubdomain: 'base-tornado',
pollInterval: 2,
constants: {
NOTE_ACCOUNT_BLOCK: 23149794,
ENCRYPTED_NOTES_BLOCK: 23149794,
},
},
[NetId.BLAST]: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 0.001,
fast: 0.001,
standard: 0.001,
low: 0.001,
},
nativeCurrency: 'eth',
currencyName: 'ETH',
explorerUrl: 'https://blastscan.io',
merkleTreeHeight: 20,
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Blast',
deployedBlock: 12144065,
stablecoin: '0x4300000000000000000000000000000000000003',
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
routerContract: '0x0D5550d52428E7e3175bfc9550207e4ad3859b17',
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
ovmGasPriceOracleContract: '0x420000000000000000000000000000000000000F',
tornadoSubgraph: 'tornadocash/blast-tornado-subgraph',
subgraphs: {},
rpcUrls: {
Blast: {
name: 'Blast',
url: 'https://rpc.blast.io',
},
blastApi: {
name: 'BlastApi',
url: 'https://blastl2-mainnet.public.blastapi.io',
},
},
tokens: {
eth: {
instanceAddress: {
'0.001': '0x82859DC3697062c16422E9b5e8Ba1B6a6EC72c76',
'0.01': '0xA287c40411685438750a247Ca67488DEBe56EE32',
'0.1': '0x84443CFd09A48AF6eF360C6976C5392aC5023a1F',
'1': '0xd47438C816c9E7f2E2888E060936a499Af9582b3',
'10': '0x330bdFADE01eE9bF63C209Ee33102DD334618e0a',
'100': '0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD',
},
symbol: 'ETH',
decimals: 18,
},
},
relayerEnsSubdomain: 'blast-tornado',
pollInterval: 2,
constants: {
NOTE_ACCOUNT_BLOCK: 12144065,
ENCRYPTED_NOTES_BLOCK: 12144065,
},
},
[NetId.GNOSIS]: { [NetId.GNOSIS]: {
rpcCallRetryAttempt: 15, rpcCallRetryAttempt: 15,
gasPrices: { gasPrices: {
@ -705,7 +514,7 @@ export const defaultConfig: networkConfig = {
}, },
}, },
relayerEnsSubdomain: 'gnosis-tornado', relayerEnsSubdomain: 'gnosis-tornado',
pollInterval: 5, pollInterval: 15,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 17754564, NOTE_ACCOUNT_BLOCK: 17754564,
ENCRYPTED_NOTES_BLOCK: 17754564, ENCRYPTED_NOTES_BLOCK: 17754564,
@ -755,7 +564,7 @@ export const defaultConfig: networkConfig = {
}, },
}, },
relayerEnsSubdomain: 'avalanche-tornado', relayerEnsSubdomain: 'avalanche-tornado',
pollInterval: 2, pollInterval: 10,
constants: { constants: {
NOTE_ACCOUNT_BLOCK: 4429813, NOTE_ACCOUNT_BLOCK: 4429813,
ENCRYPTED_NOTES_BLOCK: 4429813, ENCRYPTED_NOTES_BLOCK: 4429813,
@ -790,14 +599,6 @@ export const defaultConfig: networkConfig = {
tornadoSubgraph: 'tornadocash/sepolia-tornado-subgraph', tornadoSubgraph: 'tornadocash/sepolia-tornado-subgraph',
subgraphs: {}, subgraphs: {},
rpcUrls: { rpcUrls: {
oneRpc: {
name: '1RPC',
url: 'https://1rpc.io/sepolia',
},
tornadoRpc: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com/sepolia',
},
sepolia: { sepolia: {
name: 'Sepolia RPC', name: 'Sepolia RPC',
url: 'https://rpc.sepolia.org', url: 'https://rpc.sepolia.org',
@ -806,6 +607,10 @@ export const defaultConfig: networkConfig = {
name: 'Stackup', name: 'Stackup',
url: 'https://public.stackup.sh/api/v1/node/ethereum-sepolia', url: 'https://public.stackup.sh/api/v1/node/ethereum-sepolia',
}, },
oneRpc: {
name: '1RPC',
url: 'https://1rpc.io/sepolia',
},
ethpandaops: { ethpandaops: {
name: 'ethpandaops', name: 'ethpandaops',
url: 'https://rpc.sepolia.ethpandaops.io', url: 'https://rpc.sepolia.ethpandaops.io',

View File

@ -1,5 +1,15 @@
import { ERC20Permit, ERC20Mock, TORN } from '@tornado/contracts'; import { ERC20Permit, ERC20Mock, TORN, PermitTornado } from '@tornado/contracts';
import { MaxUint256, Provider, Signature, Signer, TypedDataField } from 'ethers'; import {
BaseContract,
MaxUint256,
Provider,
Signature,
Signer,
solidityPackedKeccak256,
TypedDataEncoder,
TypedDataField,
} from 'ethers';
import { rBigInt } from './utils';
export interface PermitValue { export interface PermitValue {
spender: string; spender: string;
@ -77,7 +87,6 @@ export async function getPermitSignature({
); );
} }
/**
export async function getPermitCommitmentsSignature({ export async function getPermitCommitmentsSignature({
PermitTornado, PermitTornado,
Token, Token,
@ -231,4 +240,3 @@ export async function getPermit2CommitmentsSignature({
}, },
}); });
} }
**/

View File

@ -316,7 +316,7 @@ export const populateTransaction = async (
signer: TornadoWallet | TornadoVoidSigner | TornadoRpcSigner, signer: TornadoWallet | TornadoVoidSigner | TornadoRpcSigner,
tx: TransactionRequest, tx: TransactionRequest,
) => { ) => {
const provider = ((signer as TornadoRpcSigner).readonlyProvider || signer.provider) as Provider; const provider = signer.provider as Provider;
if (!tx.from) { if (!tx.from) {
tx.from = signer.address; tx.from = signer.address;
@ -381,7 +381,6 @@ export interface TornadoWalletOptions {
gasLimitBump?: number; gasLimitBump?: number;
gasFailover?: boolean; gasFailover?: boolean;
bumpNonce?: boolean; bumpNonce?: boolean;
readonlyProvider?: Provider;
} }
export class TornadoWallet extends Wallet { export class TornadoWallet extends Wallet {
@ -454,11 +453,10 @@ export class TornadoRpcSigner extends JsonRpcSigner {
gasLimitBump: number; gasLimitBump: number;
gasFailover: boolean; gasFailover: boolean;
bumpNonce: boolean; bumpNonce: boolean;
readonlyProvider?: Provider;
constructor( constructor(
provider: JsonRpcApiProvider, provider: JsonRpcApiProvider,
address: string, address: string,
{ gasPriceBump, gasLimitBump, gasFailover, bumpNonce, readonlyProvider }: TornadoWalletOptions = {}, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }: TornadoWalletOptions = {},
) { ) {
super(provider, address); super(provider, address);
// 10% bump from the recommended fee // 10% bump from the recommended fee
@ -468,7 +466,6 @@ export class TornadoRpcSigner extends JsonRpcSigner {
this.gasFailover = gasFailover ?? false; this.gasFailover = gasFailover ?? false;
// turn off bumpNonce feature for browser wallet // turn off bumpNonce feature for browser wallet
this.bumpNonce = bumpNonce ?? false; this.bumpNonce = bumpNonce ?? false;
this.readonlyProvider = readonlyProvider;
} }
async sendUncheckedTransaction(tx: TransactionRequest) { async sendUncheckedTransaction(tx: TransactionRequest) {

View File

@ -1,8 +1,8 @@
// @ts-expect-error no-websnark-types // @ts-expect-error no-websnark-types
import * as websnarkUtils from 'websnark/src/utils'; import * as websnarkUtils from '@tornado/websnark/src/utils';
// @ts-expect-error no-websnark-types // @ts-expect-error no-websnark-types
import websnarkGroth from 'websnark/src/groth16'; import websnarkGroth from '@tornado/websnark/src/groth16';
import type { Element } from 'fixed-merkle-tree'; import type { Element } from '@tornado/fixed-merkle-tree';
import { toFixedHex } from './utils'; import { toFixedHex } from './utils';
export interface snarkInputs { export interface snarkInputs {

732
yarn.lock

File diff suppressed because it is too large Load Diff