Compare commits

...

12 Commits

Author SHA1 Message Date
e132275d33 Update RPC endpoints, update deps ( 1.0.23 ) 2025-04-16 05:15:47 +00:00
bf432161fb Simplify config and use latest aggregator contract 2025-01-27 17:51:14 +00:00
a93fa4a8be Update Dockerfile 2025-01-21 18:25:31 +00:00
8d5658ee7a 🖕
They are only public IP echo provider with CORS fuck
2025-01-21 18:24:20 +00:00
d688f8a2b5 Update Dockerfile 2025-01-21 17:34:31 +00:00
0aa9f00383 Remove cross-fetch deps 2025-01-21 17:34:04 +00:00
e19f5a1373 Update Dockerfile 2024-12-23 20:52:21 +00:00
5bfef2a2ae Fixed merkleTreeWorker 2024-12-23 20:52:05 +00:00
53cb3ac414 Update Dockerfile 2024-12-23 19:09:40 +00:00
f4382f4e78 Rename package name 2024-12-23 19:09:02 +00:00
20bb8c25a1 Update Dockerfile 2024-12-23 02:56:15 +00:00
d143bc2923 1.0.20
* Use latest dependencies
* Rename package to tornado-scripts
* Added fallback RPCs
* Latest eslint support
2024-12-23 02:55:45 +00:00
61 changed files with 246744 additions and 254153 deletions

View File

@@ -1,44 +0,0 @@
module.exports = {
env: {
es2021: true,
node: true,
},
extends: [
'prettier',
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:import/recommended',
'plugin:import/typescript',
'plugin:prettier/recommended',
],
overrides: [
{
env: {
node: true,
},
files: ['.eslintrc.{js,cjs}'],
parserOptions: {
sourceType: 'script',
},
},
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: ['@typescript-eslint', 'prettier'],
rules: {
'prettier/prettier': [
'error',
{
tabWidth: 4,
printWidth: 120,
singleQuote: true,
},
],
'import/order': ['error'],
'@typescript-eslint/no-unused-vars': ['warn'],
'@typescript-eslint/no-unused-expressions': ['off'],
},
};

2
.gitattributes vendored
View File

@@ -1 +1 @@
dist/* linguist-vendored dist/**/* linguist-vendored

1
.npmrc
View File

@@ -1 +0,0 @@
@tornado:registry=https://git.tornado.ws/api/packages/tornado-packages/npm/

View File

@@ -1,13 +1,13 @@
# Dockefile from https://notes.ethereum.org/@GW1ZUbNKR5iRjjKYx6_dJQ/Bk8zsJ9xj # Dockefile from https://notes.ethereum.org/@GW1ZUbNKR5iRjjKYx6_dJQ/Bk8zsJ9xj
# FROM node:20.18.0-bullseye-slim # FROM node:22.12.0-bullseye-slim
FROM node@sha256:9b558df8f10198fcd1f48cf344c55c4442c3446b8a9a69487523b3d890a4a59e FROM node@sha256:9f385b101f66ecdf9ed9218d000cd5a35600722f0aab8112632371765109c065
# install wget, git and necessary certificates # 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/* 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 ENV GIT_REPOSITORY=https://github.com/tornadocontrib/tornado-scripts.git
# From development branch, double check with tornado.ws # From main branch, double check with git.tornado.ws and codeberg.org
ENV GIT_COMMIT_HASH=f16bb2ed12464dce4f31aa5a237bb1643989e02d ENV GIT_COMMIT_HASH=8d5658ee7aedbaa2413868c4c9e0fb453a92ae64
# clone the repository # clone the repository
RUN mkdir /app/ RUN mkdir /app/

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Tornado Cash
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -2,9 +2,7 @@
<img src="./logo2.png"> <img src="./logo2.png">
# Tornado Core (@tornado/core) # Tornado Scripts (tornado-scripts)
### 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)
@@ -12,9 +10,9 @@
</div> </div>
### About Tornado Core ### About Tornado Scripts
Tornado Core is a modern building block for Privacy Pools to build anything from custom UI or CLI tools Tornado Scripts is a modern building block for Privacy Pools to build anything from custom UI or CLI tools
+ Written in [TypeScript](https://www.typescriptlang.org/) + Written in [TypeScript](https://www.typescriptlang.org/)

2
dist/contracts.d.ts vendored
View File

@@ -1,2 +1,2 @@
export * from '@tornado/contracts'; export * from 'tornado-contracts';
export { Multicall, Multicall__factory, OffchainOracle, OffchainOracle__factory, OvmGasPriceOracle, OvmGasPriceOracle__factory, ReverseRecords, ReverseRecords__factory, ENSNameWrapper, ENSNameWrapper__factory, ENSRegistry, ENSRegistry__factory, ENSResolver, ENSResolver__factory, } from './typechain'; export { Multicall, Multicall__factory, OffchainOracle, OffchainOracle__factory, OvmGasPriceOracle, OvmGasPriceOracle__factory, ReverseRecords, ReverseRecords__factory, ENSNameWrapper, ENSNameWrapper__factory, ENSRegistry, ENSRegistry__factory, ENSResolver, ENSResolver__factory, } from './typechain';

6
dist/ens.d.ts vendored
View File

@@ -8,13 +8,11 @@ export declare function makeLabelNodeAndParent(name: string): {
labelhash: string; labelhash: string;
parentNode: string; parentNode: string;
}; };
export declare const EnsContracts: { export declare const EnsContracts: Record<NetIdType, {
[key: NetIdType]: {
ensRegistry: string; ensRegistry: string;
ensPublicResolver: string; ensPublicResolver: string;
ensNameWrapper: string; ensNameWrapper: string;
}; }>;
};
/** /**
* ENSUtils to manage on-chain registered relayers * ENSUtils to manage on-chain registered relayers
*/ */

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

@@ -1,9 +1,9 @@
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, TovarishAggregator } from 'tornado-contracts';
import type { MerkleTree } from 'fixed-merkle-tree'; import type { MerkleTree } from '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 { TornadoConfig, 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 { ERC20, ReverseRecords } from '../typechain';
@@ -98,16 +98,12 @@ export declare class BaseTornadoService extends BaseEventsService<DepositsEvents
}): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>>; }): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>>;
} }
export interface BaseMultiTornadoServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> { export interface BaseMultiTornadoServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
instances: { instances: Record<string, DepositType>;
[key in string]: DepositType;
};
optionalTree?: boolean; optionalTree?: boolean;
merkleTreeService?: MerkleTreeService; merkleTreeService?: MerkleTreeService;
} }
export declare class BaseMultiTornadoService extends BaseEventsService<MultiDepositsEvents | MultiWithdrawalsEvents> { export declare class BaseMultiTornadoService extends BaseEventsService<MultiDepositsEvents | MultiWithdrawalsEvents> {
instances: { instances: Record<string, DepositType>;
[key in string]: DepositType;
};
optionalTree?: boolean; optionalTree?: boolean;
merkleTreeService?: MerkleTreeService; merkleTreeService?: MerkleTreeService;
batchTransactionService: BatchTransactionService; batchTransactionService: BatchTransactionService;
@@ -143,9 +139,7 @@ export declare class BaseEncryptedNotesService extends BaseEventsService<Encrypt
getTovarishType(): string; getTovarishType(): string;
formatEvents(events: EventLog[]): Promise<EncryptedNotesEvents[]>; formatEvents(events: EventLog[]): Promise<EncryptedNotesEvents[]>;
} }
export declare const proposalState: { export declare const proposalState: Record<string, string>;
[key: string]: string;
};
export interface GovernanceProposals extends GovernanceProposalCreatedEvents { export interface GovernanceProposals extends GovernanceProposalCreatedEvents {
title: string; title: string;
proposerName?: string; proposerName?: string;
@@ -164,12 +158,12 @@ export interface GovernanceVotes extends GovernanceVotedEvents {
} }
export interface BaseGovernanceServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> { export interface BaseGovernanceServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
Governance: Governance; Governance: Governance;
Aggregator: Aggregator; Aggregator: TovarishAggregator;
ReverseRecords: ReverseRecords; ReverseRecords: ReverseRecords;
} }
export declare class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents> { export declare class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents> {
Governance: Governance; Governance: Governance;
Aggregator: Aggregator; Aggregator: TovarishAggregator;
ReverseRecords: ReverseRecords; ReverseRecords: ReverseRecords;
batchTransactionService: BatchTransactionService; batchTransactionService: BatchTransactionService;
constructor(serviceConstructor: BaseGovernanceServiceConstructor); constructor(serviceConstructor: BaseGovernanceServiceConstructor);
@@ -182,14 +176,11 @@ export declare class BaseGovernanceService extends BaseEventsService<AllGovernan
delegatedAccs: string[]; delegatedAccs: string[];
undelegatedAccs: string[]; undelegatedAccs: string[];
uniq: string[]; uniq: string[];
uniqNames: { uniqNames: Record<string, string>;
[key: string]: string;
};
balances: bigint[]; balances: bigint[];
balance: bigint; balance: bigint;
}>; }>;
} }
export declare function getTovarishNetworks(registryService: BaseRegistryService, relayers: CachedRelayerInfo[]): Promise<void>;
/** /**
* Essential params: * Essential params:
* ensName, relayerAddress, hostnames * ensName, relayerAddress, hostnames
@@ -197,49 +188,26 @@ export declare function getTovarishNetworks(registryService: BaseRegistryService
*/ */
export interface CachedRelayerInfo extends RelayerParams { export interface CachedRelayerInfo extends RelayerParams {
isRegistered?: boolean; isRegistered?: boolean;
registeredAddress?: string; isPrior?: boolean;
stakeBalance?: string; stakeBalance?: string;
hostnames: SubdomainMap; hostnames: SubdomainMap;
tovarishHost?: string; tovarishHost?: string;
tovarishNetworks?: number[]; tovarishNetworks?: number[];
} }
export interface CachedRelayers {
lastBlock: number;
timestamp: number;
relayers: CachedRelayerInfo[];
fromCache?: boolean;
}
export interface BaseRegistryServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> { export interface BaseRegistryServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
tornadoConfig: TornadoConfig;
RelayerRegistry: RelayerRegistry; RelayerRegistry: RelayerRegistry;
Aggregator: Aggregator; Aggregator: TovarishAggregator;
relayerEnsSubdomains: SubdomainMap;
} }
export declare class BaseRegistryService extends BaseEventsService<AllRelayerRegistryEvents> { export declare class BaseRegistryService extends BaseEventsService<AllRelayerRegistryEvents> {
Aggregator: Aggregator; tornadoConfig: TornadoConfig;
relayerEnsSubdomains: SubdomainMap; Aggregator: TovarishAggregator;
updateInterval: number; updateInterval: number;
constructor(serviceConstructor: BaseRegistryServiceConstructor); constructor(serviceConstructor: BaseRegistryServiceConstructor);
getInstanceName(): string; getInstanceName(): string;
getTovarishType(): string; getTovarishType(): string;
formatEvents(events: EventLog[]): Promise<AllRelayerRegistryEvents[]>; formatEvents(events: EventLog[]): Promise<AllRelayerRegistryEvents[]>;
/** getLatestRelayers(knownRelayers?: string[]): Promise<CachedRelayerInfo[]>;
* Get saved or cached relayers
*/
getRelayersFromDB(): Promise<CachedRelayers>;
/**
* Relayers from remote cache (Either from local cache, CDN, or from IPFS)
*/
getRelayersFromCache(): Promise<CachedRelayers>;
getSavedRelayers(): Promise<CachedRelayers>;
getLatestRelayers(): Promise<CachedRelayers>;
/**
* Handle saving relayers
*/
saveRelayers({ lastBlock, timestamp, relayers }: CachedRelayers): Promise<void>;
/**
* Get cached or latest relayer and save to local
*/
updateRelayers(): Promise<CachedRelayers>;
} }
export interface BaseRevenueServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> { export interface BaseRevenueServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
RelayerRegistry: RelayerRegistry; RelayerRegistry: RelayerRegistry;

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

@@ -1,5 +1,5 @@
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, BaseMultiTornadoService, BaseMultiTornadoServiceConstructor } 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, MultiDepositsEvents, MultiWithdrawalsEvents } from './types';
export declare function saveDBEvents<T extends MinimalEvents>({ idb, instanceName, newEvents, lastBlock, }: { export declare function saveDBEvents<T extends MinimalEvents>({ idb, instanceName, newEvents, lastBlock, }: {
idb: IndexedDB; idb: IndexedDB;
@@ -100,16 +100,12 @@ export declare class DBRegistryService extends BaseRegistryService {
staticUrl: string; staticUrl: string;
idb: IndexedDB; idb: IndexedDB;
zipDigest?: string; zipDigest?: string;
relayerJsonDigest?: string;
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({ newEvents, lastBlock, }: BaseEvents<AllRelayerRegistryEvents> & {
newEvents: AllRelayerRegistryEvents[]; newEvents: AllRelayerRegistryEvents[];
}): Promise<void>; }): Promise<void>;
getRelayersFromDB(): Promise<CachedRelayers>;
getRelayersFromCache(): Promise<CachedRelayers>;
saveRelayers(cachedRelayers: CachedRelayers): Promise<void>;
} }
export interface DBRevenueServiceConstructor extends BaseRevenueServiceConstructor { export interface DBRevenueServiceConstructor extends BaseRevenueServiceConstructor {
staticUrl: string; staticUrl: string;

8
dist/gaszip.d.ts vendored
View File

@@ -1,10 +1,6 @@
import { NetIdType } from './networkConfig'; import { NetIdType } from './networkConfig';
export declare const gasZipInbounds: { export declare const gasZipInbounds: Record<NetIdType, string>;
[key in NetIdType]: string; export declare const gasZipID: Record<NetIdType, number>;
};
export declare const gasZipID: {
[key in NetIdType]: number;
};
export declare function gasZipInput(to: string, shorts: number[]): string | null; export declare function gasZipInput(to: string, shorts: number[]): string | null;
export declare function gasZipMinMax(ethUsd: number): { export declare function gasZipMinMax(ethUsd: number): {
min: number; min: number;

View File

@@ -12,9 +12,7 @@ export interface queryGraphParams {
graphApi: string; graphApi: string;
subgraphName: string; subgraphName: string;
query: string; query: string;
variables?: { variables?: Record<string, string | number>;
[key: string]: string | number;
};
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
} }
export declare function queryGraph<T>({ graphApi, subgraphName, query, variables, fetchDataOptions, }: queryGraphParams): Promise<T>; export declare function queryGraph<T>({ graphApi, subgraphName, query, variables, fetchDataOptions, }: queryGraphParams): Promise<T>;

18
dist/hashes.json vendored
View File

@@ -1,11 +1,11 @@
{ {
"dist/index.js": "sha384-txpjgDLxNbeXsLgVCyNAwpaJRS0SmFN/ITfadSo8+xzSvLqwa5bQ9GoxQ1Su8QEr", "dist/index.js": "sha384-ILYwPMkfXtfslWBdxqmKYYq4yDnJf3tKKgW5Am0P4NnpLW9z5m/wlLBuITa51727",
"dist/index.mjs": "sha384-CrEHmX4zKIv/68CKWElNzvKk6FWRMMkKV8JmqL1KqYCxO73LPEAjDqxTYpxUuDBy", "dist/index.mjs": "sha384-bgbAMKtG/iKiZKdITr1E+i14xCVp17/Yj8/O5bCE8BMnqlwTY/XvmLe8+EWmvB/s",
"dist/merkleTreeWorker.js": "sha384-XVv9HRGDZlaF0LeEZNQygle31UY6yvIwsZ4GWCTZUX7O/hZ7N5Zwpi3GqnHSBYzW", "dist/merkleTreeWorker.js": "sha384-CJID2MqR6z42NYw9ZXhHAZ05+7YrQg0YJDwJLB/qhOhIJYt3am2wVZdR/W7njnuZ",
"dist/merkleTreeWorker.umd.js": "sha384-e5B65ZZ4IxKVOU1o02K6IL2tjJof20QCcEtD+vKe1cPmyfW2BPCHWDPIbPksIpvJ", "dist/merkleTreeWorker.umd.js": "sha384-6uVyasRLcNVbdsuJSbgzxfSQ/0yRURWhP6oULhW6jffTNJzpMWay6/ie9pQVUj78",
"dist/merkleTreeWorker.umd.min.js": "sha384-AxQv1da+lSi3gMYkdGQuR1WN1+4HB8IT3cPFa17HBj14+ZzdZN6SS1fCw5Izc2rr", "dist/merkleTreeWorker.umd.min.js": "sha384-LUERJw4t5HapI287NVtz3VtnqjXXrC7yBdxMQHpkTX8ZGOjp5fyEqYb1KENzNY9R",
"dist/tornado.umd.js": "sha384-xTUkkUTm3aBsnHCUnVGxRgieAu3z4wCwrKT1DFj8VyCk/eZZO9nq+yP4/McLRfB4", "dist/tornado.umd.js": "sha384-IXBljLi80UVwQj0arsdDbOLEQlHfXFAKbAencbqDgqyUaRs7mjsYJDFe+wPgB/ie",
"dist/tornado.umd.min.js": "sha384-ubqr6m6jEOPf7LQz0pXKmEo7tCCbNUAE+iSZWK6X/f7i4wt14rYW7pUcSzw5glth", "dist/tornado.umd.min.js": "sha384-FwrFV3WOdr2uBRdFyPIKJU+gCybthzvw6+D9GDTRAYflL+Kh8C3hUyk7qsJJGGvq",
"dist/tornadoContracts.umd.js": "sha384-bFq/cemb0bP0JbIq8p75n0UR8smQ/2Yh69pjegzSuu0upawO3sKOjehY8SjX85Xh", "dist/tornadoContracts.umd.js": "sha384-wOj+yVI78CBtmwvEn3l/ko3CEbtaqHXbx69pKraBOLOkz98HlJSSTcKs/spf0Ods",
"dist/tornadoContracts.umd.min.js": "sha384-4ay7cmK0auAgZH1xfAsqyN6GtnHBNNgh9C22qy0rHxKicDzNtTsnNZDbz0qmd9GI" "dist/tornadoContracts.umd.min.js": "sha384-LMcw1ogbZefmFD6HUNEOnhIYizZEWtRW2FqUIglSxk5i1qoDq1+iZolSaGheQfx9"
} }

12
dist/idb.d.ts vendored
View File

@@ -1,5 +1,11 @@
import { OpenDBCallbacks, IDBPDatabase } from 'idb'; import type * as idb from 'idb';
import { NetIdType } from './networkConfig'; import type { OpenDBCallbacks, IDBPDatabase } from 'idb';
import type { NetIdType, TornadoConfig } from './networkConfig';
declare global {
interface Window {
idb: typeof idb;
}
}
export declare const INDEX_DB_ERROR = "A mutation operation was attempted on a database that did not allow mutations."; export declare const INDEX_DB_ERROR = "A mutation operation was attempted on a database that did not allow mutations.";
export interface IDBIndex { export interface IDBIndex {
name: string; name: string;
@@ -81,4 +87,4 @@ export declare class IndexedDB {
/** /**
* Should check if DB is initialized well * Should check if DB is initialized well
*/ */
export declare function getIndexedDB(netId?: NetIdType): Promise<IndexedDB>; export declare function getIndexedDB(netId?: NetIdType, tornadoConfig?: TornadoConfig): Promise<IndexedDB>;

2054
dist/index.js vendored

File diff suppressed because it is too large Load Diff

2031
dist/index.mjs vendored

File diff suppressed because it is too large Load Diff

16
dist/ip.d.ts vendored
View File

@@ -1,6 +1,20 @@
import { fetchDataOptions } from './providers';
export interface IPResult { export interface IPResult {
ip: string; ip: string;
iso?: string; iso?: string;
country?: string;
country_iso?: string;
tor?: boolean; tor?: boolean;
} }
export declare function fetchIp(ipEcho: string): Promise<IPResult>; export declare function fetchIp(ipEcho: string, fetchOptions?: fetchDataOptions): Promise<IPResult>;
export interface IPResultFuck {
YourFuckingIPAddress: string;
YourFuckingLocation: string;
YourFuckingHostname: string;
YourFuckingISP: string;
YourFuckingTorExit: boolean;
YourFuckingCity?: string;
YourFuckingCountry: string;
YourFuckingCountryCode: string;
}
export declare function fetchFuckingIp(ipFuck?: string, fetchOptions?: fetchDataOptions): Promise<IPResultFuck>;

View File

@@ -1,5 +1,5 @@
import { MerkleTree, PartialMerkleTree, Element, TreeEdge } from 'fixed-merkle-tree'; import { MerkleTree, PartialMerkleTree, Element, TreeEdge } from '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';
import type { NetIdType } from './networkConfig'; import type { NetIdType } from './networkConfig';

5960
dist/merkleTreeWorker.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -15,12 +15,3 @@
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */ /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */ /*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/**
* [js-sha3]{@link https://github.com/emn178/js-sha3}
*
* @version 0.8.0
* @author Chen, Yi-Cyuan [emn178@gmail.com]
* @copyright Chen, Yi-Cyuan 2015-2018
* @license MIT
*/

View File

@@ -1,4 +1,12 @@
import type { DepositType } from './deposits'; import type { DepositType } from './deposits';
export declare const MERKLE_TREE_HEIGHT = 20;
export declare const EMPTY_ELEMENT = "21663839004416932945382355908790599225266501822907911457504978515578255421292";
export declare const MULTICALL_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11";
export declare const ONEINCH_ORACLE_ADDRESS = "0x00000000000D6FFc74A8feb35aF5827bf57f6786";
export declare const TORNADO_PROXY_LIGHT_ADDRESS = "0x0D5550d52428E7e3175bfc9550207e4ad3859b17";
export declare const ECHOER_ADDRESS = "0xa75BF2815618872f155b7C4B0C81bF990f5245E4";
export declare const TOVARISH_REGISTRY_ADDRESS = "0xc9D5C487c10bC755d34029b1135FA1c190d80f9b";
export declare const TOVARISH_AGGREGATOR_ADDRESS = "0x7A51f64A277d3597475Ea28283d0423764613231";
/** /**
* Type of default supported networks * Type of default supported networks
*/ */
@@ -15,52 +23,76 @@ export declare enum NetId {
SEPOLIA = 11155111 SEPOLIA = 11155111
} }
export type NetIdType = NetId | number; export type NetIdType = NetId | number;
export interface RpcUrl { export interface TornadoInstances {
name: string; instanceAddress: Record<string, string>;
url: string;
}
export interface RpcUrls {
[key: string]: RpcUrl;
}
export interface SubgraphUrl {
name: string;
url: string;
}
export interface SubgraphUrls {
[key: string]: SubgraphUrl;
}
export interface TornadoInstance {
instanceAddress: {
[key: string]: string;
};
instanceApproval?: boolean; instanceApproval?: boolean;
optionalInstances?: string[]; optionalInstances?: string[];
isOptional?: boolean;
isDisabled?: boolean;
tokenAddress?: string; tokenAddress?: string;
tokenGasLimit?: number; tokenGasLimit?: number;
symbol: string; symbol: string;
decimals: number; decimals: number;
gasLimit?: number; gasLimit?: number;
} }
export interface TokenInstances { export interface TornadoSingleInstance {
[key: string]: TornadoInstance; netId: NetId;
instanceAddress: string;
instanceApproval?: boolean;
isOptional?: boolean;
isDisabled?: boolean;
tokenAddress?: string;
tokenGasLimit?: number;
currency: string;
amount: string;
decimals: number;
gasLimit?: number;
} }
export interface Config { export type TokenInstances = Record<string, TornadoInstances>;
rpcCallRetryAttempt?: number; export type SubdomainMap = Record<NetIdType, string>;
gasPrices: { export interface ConfigParams {
instant: number; netId: NetIdType;
fast?: number;
standard?: number;
low?: number;
maxPriorityFeePerGas?: number;
};
nativeCurrency: string;
currencyName: string;
explorerUrl: string;
merkleTreeHeight: number;
emptyElement: string;
networkName: string; networkName: string;
currencyName: string;
nativeCurrency?: string;
explorerUrl: string;
homepageUrl: string;
blockTime: number;
deployedBlock: number; deployedBlock: number;
rpcUrls: RpcUrls; merkleTreeHeight?: number;
emptyElement?: string;
stablecoin: string;
multicallContract?: string;
routerContract?: string;
echoContract?: string;
offchainOracleContract?: string;
tornContract?: string;
governanceContract?: string;
stakingRewardsContract?: string;
registryContract?: string;
tovarishRegistryContract?: string;
aggregatorContract?: string;
reverseRecordsContract?: string;
ovmGasPriceOracleContract?: string;
relayerEnsSubdomain: string;
tornadoSubgraph?: string;
registrySubgraph?: string;
governanceSubgraph?: string;
subgraphs?: string[];
rpcUrls: string[];
tokens: TokenInstances;
}
export declare class Config {
netId: NetIdType;
networkName: string;
currencyName: string;
nativeCurrency: string;
explorerUrl: string;
homepageUrl: string;
blockTime: number;
deployedBlock: number;
merkleTreeHeight?: number;
emptyElement?: string;
stablecoin: string; stablecoin: string;
multicallContract: string; multicallContract: string;
routerContract: string; routerContract: string;
@@ -70,59 +102,36 @@ export interface Config {
governanceContract?: string; governanceContract?: string;
stakingRewardsContract?: string; stakingRewardsContract?: string;
registryContract?: string; registryContract?: string;
tovarishRegistryContract?: string;
aggregatorContract?: string; aggregatorContract?: string;
reverseRecordsContract?: string; reverseRecordsContract?: string;
ovmGasPriceOracleContract?: string; ovmGasPriceOracleContract?: string;
tornadoSubgraph: string; relayerEnsSubdomain: string;
tornadoSubgraph?: string;
registrySubgraph?: string; registrySubgraph?: string;
governanceSubgraph?: string; governanceSubgraph?: string;
subgraphs: SubgraphUrls; subgraphs?: string[];
rpcUrls: string[];
tokens: TokenInstances; tokens: TokenInstances;
optionalTokens?: string[]; constructor(configParams: ConfigParams);
disabledTokens?: string[]; toJSON(): ConfigParams;
relayerEnsSubdomain: string; get allTokens(): string[];
pollInterval: number; get allSymbols(): string[];
constants: { getInstance(currency: string, amount: string): TornadoSingleInstance;
GOVERNANCE_BLOCK?: number; getInstanceByAddress(instanceAddress: string): TornadoSingleInstance;
NOTE_ACCOUNT_BLOCK?: number; get depositTypes(): Record<string, DepositType>;
ENCRYPTED_NOTES_BLOCK?: number;
REGISTRY_BLOCK?: number;
MINING_BLOCK_TIME?: number;
};
} }
export interface networkConfig { export interface TornadoConfigParams {
[key: NetIdType]: Config; configs?: Record<NetIdType, ConfigParams>;
governanceNetwork?: NetIdType;
relayerNetwork?: NetIdType;
} }
export interface SubdomainMap { export declare class TornadoConfig {
[key: NetIdType]: string; configs: Record<NetIdType, Config>;
governanceNetwork: NetIdType;
relayerNetwork: NetIdType;
constructor(configParams?: TornadoConfigParams);
get chains(): NetIdType[];
getConfig(netId: NetIdType): Config;
} }
export declare const defaultConfig: networkConfig; export declare const defaultConfig: Record<NetIdType, ConfigParams>;
export declare const enabledChains: NetIdType[];
/**
* Custom config object to extend default config
*
* Inspired by getUrlFunc from ethers.js
* https://github.com/ethers-io/ethers.js/blob/v6/src.ts/utils/fetch.ts#L59
*/
export declare let customConfig: networkConfig;
/**
* Add or override existing network config object
*
* Could be also called on the UI hook so that the UI could allow people to use custom privacy pools
*/
export declare function addNetwork(newConfig: networkConfig): void;
export declare function getNetworkConfig(): networkConfig;
export declare function getConfig(netId: NetIdType): Config;
export declare function getActiveTokens(config: Config): string[];
export declare function getActiveTokenInstances(config: Config): TokenInstances;
export declare function getInstanceByAddress(config: Config, address: string): {
amount: string;
currency: string;
symbol: string;
decimals: number;
tokenAddress: string | undefined;
} | undefined;
export declare function getRelayerEnsSubdomains(): SubdomainMap;
export declare function getMultiInstances(netId: NetIdType, config: Config): {
[key in string]: DepositType;
};

6
dist/permit.d.ts vendored
View File

@@ -1,4 +1,4 @@
import { ERC20Permit, ERC20Mock, TORN } from '@tornado/contracts'; import { ERC20Permit, ERC20Mock, TORN } from 'tornado-contracts';
import { Signature, Signer, TypedDataField } from 'ethers'; import { Signature, Signer, TypedDataField } from 'ethers';
export interface PermitValue { export interface PermitValue {
spender: string; spender: string;
@@ -18,9 +18,7 @@ export declare const permit2Address = "0x000000000022D473030F116dDEE9F6B43aC78BA
*/ */
export interface Witness { export interface Witness {
witnessTypeName: string; witnessTypeName: string;
witnessType: { witnessType: Record<string, TypedDataField[]>;
[key: string]: TypedDataField[];
};
witness: any; witness: any;
} }
export declare function getPermitSignature({ Token, signer, spender, value, nonce, deadline, }: PermitValue & { export declare function getPermitSignature({ Token, signer, spender, value, nonce, deadline, }: PermitValue & {

56
dist/providers.d.ts vendored
View File

@@ -1,7 +1,6 @@
import type { EventEmitter } from 'stream'; import type { EventEmitter } from 'stream';
import type { RequestOptions } from 'http'; import { JsonRpcApiProvider, JsonRpcProvider, Wallet, FetchGetUrlFunc, Provider, SigningKey, TransactionRequest, JsonRpcSigner, BrowserProvider, Networkish, Eip1193Provider, VoidSigner, FetchCancelSignal, TransactionLike } from 'ethers';
import { JsonRpcApiProvider, JsonRpcProvider, Wallet, FetchGetUrlFunc, Provider, SigningKey, TransactionRequest, JsonRpcSigner, BrowserProvider, Networkish, Eip1193Provider, VoidSigner, FetchCancelSignal } from 'ethers'; import type { Dispatcher, RequestInit } from 'undici-types';
import type { RequestInfo, RequestInit, Response, HeadersInit } from 'node-fetch';
import type { Config, NetIdType } from './networkConfig'; import type { Config, NetIdType } from './networkConfig';
declare global { declare global {
interface Window { interface Window {
@@ -9,35 +8,54 @@ declare global {
} }
} }
export declare const defaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0"; export declare const defaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0";
export type nodeFetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>; export type DispatcherFunc = (retry?: number) => Dispatcher;
export type fetchDataOptions = RequestInit & { export interface fetchDataOptions extends Omit<RequestInit, 'headers'> {
/**
* Overriding RequestInit params
*/
headers?: HeadersInit | any; headers?: HeadersInit | any;
/**
* Expanding RequestInit params
*/
maxRetry?: number; maxRetry?: number;
retryOn?: number; retryOn?: number;
userAgent?: string; userAgent?: string;
timeout?: number; timeout?: number;
proxy?: string;
torPort?: number;
debug?: Function; debug?: Function;
returnResponse?: boolean; returnResponse?: boolean;
cancelSignal?: FetchCancelSignal; cancelSignal?: FetchCancelSignal;
}; dispatcherFunc?: DispatcherFunc;
export type NodeAgent = RequestOptions['agent'] | ((parsedUrl: URL) => RequestOptions['agent']); }
export declare function getHttpAgent({ fetchUrl, proxyUrl, torPort, retry, }: { export declare function fetchData<T>(url: string, options?: fetchDataOptions): Promise<T>;
fetchUrl: string;
proxyUrl?: string;
torPort?: number;
retry: number;
}): NodeAgent | undefined;
export declare function fetchData(url: string, options?: fetchDataOptions): Promise<any>;
export declare const fetchGetUrlFunc: (options?: fetchDataOptions) => FetchGetUrlFunc; export declare const fetchGetUrlFunc: (options?: fetchDataOptions) => FetchGetUrlFunc;
export type getProviderOptions = fetchDataOptions & { export type getProviderOptions = fetchDataOptions & {
netId?: NetIdType; netId?: NetIdType;
pollingInterval?: number; pollingInterval?: number;
}; };
export declare const FeeDataNetworkPluginName: string;
export declare function getProvider(rpcUrl: string, fetchOptions?: getProviderOptions): Promise<JsonRpcProvider>; export declare function getProvider(rpcUrl: string, fetchOptions?: getProviderOptions): Promise<JsonRpcProvider>;
export declare function getProviderWithNetId(netId: NetIdType, rpcUrl: string, config: Config, fetchOptions?: getProviderOptions): JsonRpcProvider; export declare function getProviderWithNetId(netId: NetIdType, rpcUrl: string, config: Config, fetchOptions?: getProviderOptions): JsonRpcProvider;
export declare const populateTransaction: (signer: TornadoWallet | TornadoVoidSigner | TornadoRpcSigner, tx: TransactionRequest) => Promise<TransactionRequest>; export declare const populateTransaction: (signer: TornadoWallet | TornadoVoidSigner | TornadoRpcSigner, tx: TransactionRequest) => Promise<{
type?: null | number | undefined;
to?: string | import("ethers").Addressable | null | undefined;
from?: string | import("ethers").Addressable | null | undefined;
nonce?: null | number | undefined;
gasLimit?: string | number | bigint | null | undefined;
gasPrice?: string | number | bigint | null | undefined;
maxPriorityFeePerGas?: string | number | bigint | null | undefined;
maxFeePerGas?: string | number | bigint | null | undefined;
data?: null | string | undefined;
value?: string | number | bigint | null | undefined;
chainId?: string | number | bigint | null | undefined;
accessList?: import("ethers").AccessList | [string, string[]][] | Record<string, string[]> | null | undefined;
customData?: any;
blockTag?: string | number | bigint | undefined;
enableCcipRead?: boolean | undefined;
blobVersionedHashes?: (null | Array<string>) | undefined;
maxFeePerBlobGas?: string | number | bigint | null | undefined;
blobs?: (null | Array<import("ethers").BlobLike>) | undefined;
kzg?: (null | import("ethers").KzgLibrary) | undefined;
}>;
export interface TornadoWalletOptions { export interface TornadoWalletOptions {
gasPriceBump?: number; gasPriceBump?: number;
gasLimitBump?: number; gasLimitBump?: number;
@@ -53,7 +71,7 @@ export declare class TornadoWallet extends Wallet {
bumpNonce: boolean; bumpNonce: boolean;
constructor(key: string | SigningKey, provider?: Provider, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }?: TornadoWalletOptions); constructor(key: string | SigningKey, provider?: Provider, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }?: TornadoWalletOptions);
static fromMnemonic(mneomnic: string, provider: Provider, index?: number, options?: TornadoWalletOptions): TornadoWallet; static fromMnemonic(mneomnic: string, provider: Provider, index?: number, options?: TornadoWalletOptions): TornadoWallet;
populateTransaction(tx: TransactionRequest): Promise<import("ethers").TransactionLike<string>>; populateTransaction(tx: TransactionRequest): Promise<TransactionLike<string>>;
} }
export declare class TornadoVoidSigner extends VoidSigner { export declare class TornadoVoidSigner extends VoidSigner {
nonce?: number; nonce?: number;
@@ -62,7 +80,7 @@ export declare class TornadoVoidSigner extends VoidSigner {
gasFailover: boolean; gasFailover: boolean;
bumpNonce: boolean; bumpNonce: boolean;
constructor(address: string, provider?: Provider, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }?: TornadoWalletOptions); constructor(address: string, provider?: Provider, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }?: TornadoWalletOptions);
populateTransaction(tx: TransactionRequest): Promise<import("ethers").TransactionLike<string>>; populateTransaction(tx: TransactionRequest): Promise<TransactionLike<string>>;
} }
export declare class TornadoRpcSigner extends JsonRpcSigner { export declare class TornadoRpcSigner extends JsonRpcSigner {
nonce?: number; nonce?: number;

View File

@@ -1,4 +1,4 @@
import { NetIdType, Config } from './networkConfig'; import type { NetIdType, TornadoConfig } from './networkConfig';
import { fetchDataOptions } from './providers'; import { fetchDataOptions } from './providers';
import type { snarkProofs } from './websnark'; import type { snarkProofs } from './websnark';
import type { CachedRelayerInfo } from './events'; import type { CachedRelayerInfo } from './events';
@@ -20,9 +20,7 @@ export interface RelayerInfo extends RelayerParams {
instances: string[]; instances: string[];
stakeBalance?: string; stakeBalance?: string;
gasPrice?: number; gasPrice?: number;
ethPrices?: { ethPrices?: Record<string, string>;
[key in string]: string;
};
currentQueue: number; currentQueue: number;
tornadoServiceFee: number; tornadoServiceFee: number;
} }
@@ -35,24 +33,18 @@ export interface RelayerError {
export interface RelayerStatus { export interface RelayerStatus {
url: string; url: string;
rewardAccount: string; rewardAccount: string;
instances: { instances: Record<string, {
[key in string]: { instanceAddress: Record<string, string>;
instanceAddress: {
[key in string]: string;
};
tokenAddress?: string; tokenAddress?: string;
symbol: string; symbol: string;
decimals: number; decimals: number;
}; }>;
};
gasPrices?: { gasPrices?: {
fast: number; fast: number;
additionalProperties?: number; additionalProperties?: number;
}; };
netId: NetIdType; netId: NetIdType;
ethPrices?: { ethPrices?: Record<string, string>;
[key in string]: string;
};
tornadoServiceFee: number; tornadoServiceFee: number;
latestBlock?: number; latestBlock?: number;
version: string; version: string;
@@ -111,34 +103,28 @@ export function isRelayerUpdated(relayerVersion: string, netId: NetIdType) {
**/ **/
export declare function calculateScore({ stakeBalance, tornadoServiceFee }: RelayerInfo): bigint; export declare function calculateScore({ stakeBalance, tornadoServiceFee }: RelayerInfo): bigint;
export declare function getWeightRandom(weightsScores: bigint[], random: bigint): number; export declare function getWeightRandom(weightsScores: bigint[], random: bigint): number;
export interface RelayerInstanceList { export type RelayerInstanceList = Record<string, {
[key: string]: { instanceAddress: Record<string, string>;
instanceAddress: { }>;
[key: string]: string;
};
};
}
export declare function getSupportedInstances(instanceList: RelayerInstanceList): string[]; export declare function getSupportedInstances(instanceList: RelayerInstanceList): string[];
export declare function pickWeightedRandomRelayer(relayers: RelayerInfo[]): RelayerInfo; export declare function pickWeightedRandomRelayer(relayers: RelayerInfo[]): RelayerInfo;
export interface RelayerClientConstructor { export interface RelayerClientConstructor {
netId: NetIdType; tornadoConfig: TornadoConfig;
config: Config;
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
} }
export declare class RelayerClient { export declare class RelayerClient {
netId: NetIdType; tornadoConfig: TornadoConfig;
config: Config;
selectedRelayer?: RelayerInfo; selectedRelayer?: RelayerInfo;
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
tovarish: boolean; tovarish: boolean;
constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor); constructor({ tornadoConfig, fetchDataOptions }: RelayerClientConstructor);
askRelayerStatus({ hostname, url, relayerAddress, }: { askRelayerStatus({ netId, hostname, url, }: {
netId: NetIdType;
hostname?: string; hostname?: string;
url?: string; url?: string;
relayerAddress?: string;
}): Promise<RelayerStatus>; }): Promise<RelayerStatus>;
filterRelayer(relayer: CachedRelayerInfo): Promise<RelayerInfo | RelayerError | undefined>; filterRelayer(netId: NetIdType, relayer: CachedRelayerInfo): Promise<RelayerInfo | RelayerError | undefined>;
getValidRelayers(relayers: CachedRelayerInfo[]): Promise<{ getValidRelayers(netId: NetIdType, relayers: CachedRelayerInfo[]): Promise<{
validRelayers: RelayerInfo[]; validRelayers: RelayerInfo[];
invalidRelayers: RelayerError[]; invalidRelayers: RelayerError[];
}>; }>;

View File

@@ -1,18 +1,16 @@
import { Config, NetIdType } from '../networkConfig'; import { Config } from '../networkConfig';
import { addressSchemaType, bnSchemaType } from '.'; import { addressSchemaType, bnSchemaType } from '.';
export interface statusInstanceType { export interface statusInstanceType {
type: string; type: string;
properties: { properties: {
instanceAddress: { instanceAddress: {
type: string; type: string;
properties: { properties: Record<string, typeof addressSchemaType>;
[key in string]: typeof addressSchemaType;
};
required: string[]; required: string[];
}; };
tokenAddress?: typeof addressSchemaType; tokenAddress?: typeof addressSchemaType;
symbol?: { symbol?: {
enum: string[]; type: string;
}; };
decimals: { decimals: {
enum: number[]; enum: number[];
@@ -22,16 +20,12 @@ export interface statusInstanceType {
} }
export interface statusInstancesType { export interface statusInstancesType {
type: string; type: string;
properties: { properties: Record<string, statusInstanceType>;
[key in string]: statusInstanceType;
};
required: string[]; required: string[];
} }
export interface statusEthPricesType { export interface statusEthPricesType {
type: string; type: string;
properties: { properties: Record<string, typeof bnSchemaType>;
[key in string]: typeof bnSchemaType;
};
required?: string[]; required?: string[];
} }
export interface statusSchema { export interface statusSchema {
@@ -41,11 +35,9 @@ export interface statusSchema {
instances?: statusInstancesType; instances?: statusInstancesType;
gasPrices: { gasPrices: {
type: string; type: string;
properties: { properties: Record<string, {
[key in string]: {
type: string; type: string;
}; }>;
};
required: string[]; required: string[];
}; };
netId: { netId: {
@@ -103,4 +95,4 @@ export interface statusSchema {
}; };
required: string[]; required: string[];
} }
export declare function getStatusSchema(netId: NetIdType, config: Config, tovarish: boolean): statusSchema; export declare function getStatusSchema(config: Config, tovarish: boolean): statusSchema;

334346
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

View File

@@ -23,12 +23,3 @@
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */ /*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */ /*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */
/**
* [js-sha3]{@link https://github.com/emn178/js-sha3}
*
* @version 0.8.0
* @author Chen, Yi-Cyuan [emn178@gmail.com]
* @copyright Chen, Yi-Cyuan 2015-2018
* @license MIT
*/

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,6 @@
import { RelayerClient, RelayerClientConstructor, RelayerError, RelayerInfo, RelayerStatus } from './relayerClient'; import { RelayerClient, RelayerClientConstructor, RelayerError, RelayerInfo, RelayerStatus } from './relayerClient';
import { CachedRelayerInfo, MinimalEvents } from './events'; import { CachedRelayerInfo, MinimalEvents } from './events';
import { NetIdType } from './networkConfig';
export declare const MAX_TOVARISH_EVENTS = 5000; export declare const MAX_TOVARISH_EVENTS = 5000;
export interface EventsStatus { export interface EventsStatus {
events: number; events: number;
@@ -45,7 +46,8 @@ export interface BaseTovarishEvents<T> {
export declare class TovarishClient extends RelayerClient { export declare class TovarishClient extends RelayerClient {
selectedRelayer?: TovarishInfo; selectedRelayer?: TovarishInfo;
constructor(clientConstructor: RelayerClientConstructor); constructor(clientConstructor: RelayerClientConstructor);
askRelayerStatus({ hostname, url, relayerAddress, }: { askRelayerStatus({ netId, hostname, url, }: {
netId: NetIdType;
hostname?: string; hostname?: string;
url?: string; url?: string;
relayerAddress?: string; relayerAddress?: string;
@@ -58,8 +60,8 @@ export declare class TovarishClient extends RelayerClient {
url?: string; url?: string;
relayerAddress?: string; relayerAddress?: string;
}): Promise<TovarishStatus[]>; }): Promise<TovarishStatus[]>;
filterRelayer(relayer: CachedRelayerInfo): Promise<TovarishInfo | RelayerError | undefined>; filterRelayer(netId: NetIdType, relayer: CachedRelayerInfo): Promise<TovarishInfo | RelayerError | undefined>;
getValidRelayers(relayers: CachedRelayerInfo[]): Promise<{ getValidRelayers(netId: NetIdType, relayers: CachedRelayerInfo[]): Promise<{
validRelayers: TovarishInfo[]; validRelayers: TovarishInfo[];
invalidRelayers: RelayerError[]; invalidRelayers: RelayerError[];
}>; }>;

12
dist/utils.d.ts vendored
View File

@@ -8,22 +8,22 @@ export declare const chunk: <T>(arr: T[], size: number) => T[][];
export declare function sleep(ms: number): Promise<unknown>; export declare function sleep(ms: number): Promise<unknown>;
export declare function validateUrl(url: string, protocols?: string[]): boolean; export declare function validateUrl(url: string, protocols?: string[]): boolean;
export declare function concatBytes(...arrays: Uint8Array[]): Uint8Array; export declare function concatBytes(...arrays: Uint8Array[]): Uint8Array;
export declare function bufferToBytes(b: Buffer): Uint8Array; export declare function bufferToBytes(b: Buffer): Uint8Array<ArrayBufferLike>;
export declare function bytesToBase64(bytes: Uint8Array): string; export declare function bytesToBase64(bytes: Uint8Array): string;
export declare function base64ToBytes(base64: string): Uint8Array; export declare function base64ToBytes(base64: string): Uint8Array<ArrayBuffer>;
export declare function bytesToHex(bytes: Uint8Array): string; export declare function bytesToHex(bytes: Uint8Array): string;
export declare function hexToBytes(hexString: string): Uint8Array; export declare function hexToBytes(hexString: string): Uint8Array<ArrayBuffer>;
export declare function bytesToBN(bytes: Uint8Array): bigint; export declare function bytesToBN(bytes: Uint8Array): bigint;
export declare function bnToBytes(bigint: bigint | string): Uint8Array; export declare function bnToBytes(bigint: bigint | string): Uint8Array<ArrayBuffer>;
export declare function leBuff2Int(bytes: Uint8Array): BN; export declare function leBuff2Int(bytes: Uint8Array): BN;
export declare function leInt2Buff(bigint: bnInput | bigint): Uint8Array; export declare function leInt2Buff(bigint: bnInput | bigint): Uint8Array<ArrayBuffer>;
export declare function toFixedHex(numberish: BigNumberish, length?: number): string; export declare function toFixedHex(numberish: BigNumberish, length?: number): string;
export declare function toFixedLength(string: string, length?: number): string; export declare function toFixedLength(string: string, length?: number): string;
export declare function rBigInt(nbytes?: number): bigint; export declare function rBigInt(nbytes?: number): bigint;
export declare function rHex(nbytes?: number): string; export declare function rHex(nbytes?: number): string;
export declare function bigIntReplacer(key: any, value: any): any; export declare function bigIntReplacer(key: any, value: any): any;
export declare function substring(str: string, length?: number): string; export declare function substring(str: string, length?: number): string;
export declare function digest(bytes: Uint8Array, algo?: string): Promise<Uint8Array>; export declare function digest(bytes: Uint8Array, algo?: string): Promise<Uint8Array<ArrayBuffer>>;
export declare function numberFormatter(num: string | number | bigint, digits?: number): string; export declare function numberFormatter(num: string | number | bigint, digits?: number): string;
export declare function isHex(value: string): boolean; export declare function isHex(value: string): boolean;
export declare function toContentHash(ipfsUrl: string): any; export declare function toContentHash(ipfsUrl: string): any;

8
dist/zip.d.ts vendored
View File

@@ -1,9 +1,13 @@
import { AsyncZippable, Unzipped, ZipAttributes } from 'fflate'; import { AsyncZippable, Unzipped, ZipAttributes, AsyncZlibOptions, AsyncUnzlibOptions } from 'fflate';
import { fetchDataOptions } from './providers';
export declare function zipAsync(file: AsyncZippable, options?: ZipAttributes): Promise<Uint8Array>; export declare function zipAsync(file: AsyncZippable, options?: ZipAttributes): Promise<Uint8Array>;
export declare function unzipAsync(data: Uint8Array): Promise<Unzipped>; export declare function unzipAsync(data: Uint8Array): Promise<Unzipped>;
export declare function downloadZip<T>({ staticUrl, zipName, zipDigest, parseJson, }: { export declare function zlibAsync(data: Uint8Array, options?: AsyncZlibOptions): Promise<Uint8Array>;
export declare function unzlibAsync(data: Uint8Array, options?: AsyncUnzlibOptions): Promise<Uint8Array>;
export declare function downloadZip<T>({ staticUrl, zipName, zipDigest, parseJson, fetchOptions, }: {
staticUrl?: string; staticUrl?: string;
zipName: string; zipName: string;
zipDigest?: string; zipDigest?: string;
parseJson?: boolean; parseJson?: boolean;
fetchOptions?: fetchDataOptions;
}): Promise<T>; }): Promise<T>;

55
eslint.config.mjs Normal file
View File

@@ -0,0 +1,55 @@
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import importPlugin from 'eslint-plugin-import';
import prettierRecommendedConfig from 'eslint-plugin-prettier/recommended';
export default tseslint.config(
{
files: ['**/*.js', '**/*.mjs', '**/*.ts', '**/*.tsx'],
extends: [eslint.configs.recommended, prettierRecommendedConfig],
languageOptions: {
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
},
rules: {
'prettier/prettier': [
'error',
{
tabWidth: 4,
printWidth: 120,
singleQuote: true,
},
],
},
},
{
files: ['**/*.ts', '**/*.tsx'],
extends: [
...tseslint.configs.recommended,
...tseslint.configs.stylistic,
importPlugin.flatConfigs.recommended,
importPlugin.flatConfigs.typescript,
],
rules: {
'import/order': ['error'],
'@typescript-eslint/no-unused-vars': ['warn'],
'@typescript-eslint/no-unused-expressions': ['off'],
'@typescript-eslint/no-empty-function': ['off'],
},
settings: {
'import/resolver': {
typescript: {
alwaysTryTypes: true,
project: './tsconfig.json',
},
},
},
languageOptions: {
parserOptions: {
projectService: true,
},
},
},
);

View File

@@ -1,6 +1,6 @@
{ {
"name": "@tornado/core", "name": "tornado-scripts",
"version": "1.0.19", "version": "1.0.23",
"description": "An SDK for building applications on top of Privacy Pools", "description": "An SDK for building applications on top of Privacy Pools",
"main": "./dist/index.js", "main": "./dist/index.js",
"module": "./dist/index.mjs", "module": "./dist/index.mjs",
@@ -10,98 +10,99 @@
"scripts": { "scripts": {
"typechain": "typechain --target ethers-v6 --out-dir src/typechain src/abi/*.json", "typechain": "typechain --target ethers-v6 --out-dir src/typechain src/abi/*.json",
"types": "tsc --declaration --emitDeclarationOnly -p tsconfig.build.json", "types": "tsc --declaration --emitDeclarationOnly -p tsconfig.build.json",
"lint": "eslint src/**/*.ts test/**/*.ts --ext .ts --ignore-pattern src/typechain", "lint": "eslint src/**/*.ts test/**/*.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:hash": "ts-node scripts/hash.ts",
"build": "yarn types && yarn build:node && yarn build:web && yarn build:hash", "build": "yarn types && yarn build:node && yarn build:web && yarn build:hash",
"ipfs:build": "docker build -t tornado-core .", "docker:build": "docker build -t tornado-scripts .",
"ipfs:hash": "docker container run --rm -it --entrypoint cat tornado-core /app/dist/hashes.json", "docker:hash": "docker container run --rm -it --entrypoint cat tornado-scripts /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 --timeout 300000 --recursive test/**/*.ts"
}, },
"author": "", "author": "Tornado Contrib",
"license": "MIT", "license": "MIT",
"files": [ "files": [
"dist", "dist",
"scripts",
"src", "src",
".eslintrc.js", "test",
".gitattributes", ".gitattributes",
".gitignore", ".gitignore",
".npmrc", "Dockerfile",
"eslint.config.mjs",
"hardhat.config.ts",
"LICENSE",
"logo.png", "logo.png",
"logo2.png", "logo2.png",
"rollup.config.mjs", "rollup.config.mjs",
"tsconfig.build.json",
"tsconfig.json", "tsconfig.json",
"webpack.config.js",
"yarn.lock" "yarn.lock"
], ],
"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.2.0",
"@tornado/contracts": "git+https://git.tornado.ws/tornadocontrib/tornado-contracts.git#093ae2210e1f1b016b756b4db200c4a1b3308408",
"ajv": "^8.17.1", "ajv": "^8.17.1",
"bn.js": "^5.2.1", "bn.js": "^5.2.1",
"circomlibjs": "0.1.7", "circomlibjs": "git+https://github.com/tornadocontrib/circomlibjs.git#2aef7aade8e2b8d103250e4b24c7f1526cf1dd8d",
"cross-fetch": "^4.0.0", "ethers": "^6.13.5",
"ethers": "^6.13.4", "ffjavascript": "git+https://github.com/tornadocontrib/ffjavascript.git#fc766f09818d46967d1329c0fc8e361d8b349109",
"ffjavascript": "0.2.48",
"fflate": "^0.8.2", "fflate": "^0.8.2",
"fixed-merkle-tree": "0.7.3", "fixed-merkle-tree": "0.7.3",
"idb": "^8.0.0",
"snarkjs": "git+https://github.com/tornadocontrib/snarkjs.git#2c964b3fe6019e057acab04cc17705d1f7fdaf9a", "snarkjs": "git+https://github.com/tornadocontrib/snarkjs.git#2c964b3fe6019e057acab04cc17705d1f7fdaf9a",
"websnark": "git+https://github.com/tornadocontrib/websnark.git#f0ddbf34b3045cac9e6d3e4d977bf3b439869fae" "tornado-contracts": "git+https://github.com/tornadocontrib/tornado-contracts.git#a1c8fbd2919996a642a7de1abec86548ff64449b",
"websnark": "git+https://github.com/tornadocontrib/websnark.git#e5a79cca905d1ffb61a69739492be58d438c9f17"
}, },
"devDependencies": { "devDependencies": {
"@nomicfoundation/hardhat-chai-matchers": "^2.0.7", "@nomicfoundation/hardhat-chai-matchers": "^2.0.8",
"@nomicfoundation/hardhat-ethers": "^3.0.8", "@nomicfoundation/hardhat-ethers": "^3.0.8",
"@nomicfoundation/hardhat-ignition": "^0.15.5", "@nomicfoundation/hardhat-ignition": "^0.15.11",
"@nomicfoundation/hardhat-ignition-ethers": "^0.15.5", "@nomicfoundation/hardhat-ignition-ethers": "^0.15.11",
"@nomicfoundation/hardhat-network-helpers": "^1.0.11", "@nomicfoundation/hardhat-network-helpers": "^1.0.12",
"@nomicfoundation/hardhat-toolbox": "^5.0.0", "@nomicfoundation/hardhat-toolbox": "^5.0.0",
"@nomicfoundation/hardhat-verify": "^2.0.10", "@nomicfoundation/hardhat-verify": "^2.0.13",
"@nomicfoundation/ignition-core": "^0.15.5", "@rollup/plugin-commonjs": "^28.0.3",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0", "@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-node-resolve": "^16.0.1",
"@typechain/ethers-v6": "^0.5.1", "@typechain/ethers-v6": "^0.5.1",
"@typechain/hardhat": "^9.1.0", "@typechain/hardhat": "^9.1.0",
"@types/bn.js": "^5.1.6", "@types/bn.js": "^5.1.6",
"@types/chai": "^4.2.0", "@types/chai": "^5.2.1",
"@types/circomlibjs": "^0.1.6", "@types/circomlibjs": "^0.1.6",
"@types/mocha": "^10.0.9", "@types/mocha": "^10.0.10",
"@types/node": "^22.8.0", "@types/node": "^22.14.1",
"@types/node-fetch": "^2.6.11", "chai": "^4.5.0",
"@typescript-eslint/eslint-plugin": "^8.11.0", "esbuild-loader": "^4.3.0",
"@typescript-eslint/parser": "^8.11.0", "eslint": "^9.24.0",
"chai": "4.5.0", "eslint-config-prettier": "^10.1.2",
"esbuild-loader": "^4.2.2", "eslint-import-resolver-typescript": "^4.3.2",
"eslint": "8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import": "^2.31.0", "eslint-plugin-import": "^2.31.0",
"eslint-plugin-prettier": "^5.2.1", "eslint-plugin-prettier": "^5.2.6",
"fetch-mock": "^12.0.2", "fetch-mock": "^12.5.2",
"hardhat": "^2.22.10", "hardhat": "^2.23.0",
"hardhat-gas-reporter": "^2.2.1", "hardhat-gas-reporter": "^2.2.3",
"mocha": "^10.7.3", "idb": "^8.0.2",
"node-polyfill-webpack-plugin": "^4.0.0", "mocha": "^11.1.0",
"node-polyfill-webpack-plugin": "^4.1.0",
"nyc": "^17.1.0", "nyc": "^17.1.0",
"prettier": "^3.3.3", "prettier": "^3.5.3",
"rollup": "^4.24.0", "rollup": "^4.40.0",
"rollup-plugin-esbuild": "^6.1.1", "rollup-plugin-esbuild": "^6.2.1",
"solidity-coverage": "^0.8.13", "solidity-coverage": "^0.8.15",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"tsc": "^2.0.4", "tsc": "^2.0.4",
"typechain": "^8.3.2", "typechain": "^8.3.2",
"typescript": "^5.6.3", "typescript": "^5.8.3",
"webpack": "^5.95.0", "typescript-eslint": "^8.30.1",
"webpack-cli": "^5.1.4" "webpack": "^5.99.5",
"webpack-cli": "^6.0.1"
}, },
"resolutions": { "resolutions": {
"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", "big-integer": "1.6.52",
"ffjavascript": "0.2.48" "ffjavascript": "git+https://github.com/tornadocontrib/ffjavascript.git#fc766f09818d46967d1329c0fc8e361d8b349109"
} }
} }

View File

@@ -42,7 +42,7 @@ export async function getSubInfo(
tag: string; tag: string;
topics: TopicFilter; topics: TopicFilter;
}> { }> {
let topics: Array<null | string | Array<string>>; let topics: (null | string | string[])[];
let fragment: null | EventFragment = null; let fragment: null | EventFragment = null;
// Convert named events to topicHash and get the fragment for // Convert named events to topicHash and get the fragment for
@@ -242,7 +242,6 @@ export class BatchBlockService {
let retries = 0; let retries = 0;
let err; let err;
// eslint-disable-next-line no-unmodified-loop-condition
while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) { while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) {
try { try {
return await Promise.all(blocks.map((b) => this.getBlock(b))); return await Promise.all(blocks.map((b) => this.getBlock(b)));
@@ -346,7 +345,6 @@ export class BatchTransactionService {
let retries = 0; let retries = 0;
let err; let err;
// eslint-disable-next-line no-unmodified-loop-condition
while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) { while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) {
try { try {
if (!receipt) { if (!receipt) {
@@ -491,7 +489,6 @@ export class BatchEventsService {
let err; let err;
let retries = 0; let retries = 0;
// eslint-disable-next-line no-unmodified-loop-condition
while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) { while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) {
try { try {
if (this.address) { if (this.address) {

View File

@@ -1,4 +1,4 @@
export * from '@tornado/contracts'; export * from 'tornado-contracts';
export { export {
Multicall, Multicall,
Multicall__factory, Multicall__factory,

View File

@@ -40,13 +40,14 @@ export function makeLabelNodeAndParent(name: string) {
} }
// https://github.com/ensdomains/ensjs/blob/main/packages/ensjs/src/contracts/consts.ts // https://github.com/ensdomains/ensjs/blob/main/packages/ensjs/src/contracts/consts.ts
export const EnsContracts: { export const EnsContracts: Record<
[key: NetIdType]: { NetIdType,
{
ensRegistry: string; ensRegistry: string;
ensPublicResolver: string; ensPublicResolver: string;
ensNameWrapper: string; ensNameWrapper: string;
}; }
} = { > = {
[NetId.MAINNET]: { [NetId.MAINNET]: {
ensRegistry: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e', ensRegistry: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
ensPublicResolver: '0x231b0Ee14048e9dCcD1d247744d114a4EB5E8E63', ensPublicResolver: '0x231b0Ee14048e9dCcD1d247744d114a4EB5E8E63',
@@ -75,7 +76,8 @@ export class ENSUtils {
async getContracts() { async getContracts() {
const { chainId } = await this.provider.getNetwork(); const { chainId } = await this.provider.getNetwork();
const { ensRegistry, ensPublicResolver, ensNameWrapper } = EnsContracts[Number(chainId)]; const { ensRegistry, ensPublicResolver, ensNameWrapper } =
EnsContracts[Number(chainId)] || EnsContracts[NetId.MAINNET];
this.ENSRegistry = ENSRegistry__factory.connect(ensRegistry, this.provider); this.ENSRegistry = ENSRegistry__factory.connect(ensRegistry, this.provider);
this.ENSResolver = ENSResolver__factory.connect(ensPublicResolver, this.provider); this.ENSResolver = ENSResolver__factory.connect(ensPublicResolver, this.provider);

View File

@@ -4,7 +4,6 @@ import {
EventLog, EventLog,
TransactionResponse, TransactionResponse,
getAddress, getAddress,
namehash,
formatEther, formatEther,
AbiCoder, AbiCoder,
dataLength, dataLength,
@@ -18,9 +17,9 @@ import {
Governance, Governance,
RelayerRegistry, RelayerRegistry,
Echoer, Echoer,
Aggregator,
Tornado__factory, Tornado__factory,
} from '@tornado/contracts'; TovarishAggregator,
} from 'tornado-contracts';
import type { MerkleTree } from 'fixed-merkle-tree'; import type { MerkleTree } from 'fixed-merkle-tree';
import { import {
@@ -31,8 +30,8 @@ import {
BatchBlockOnProgress, BatchBlockOnProgress,
} from '../batch'; } from '../batch';
import { fetchData, fetchDataOptions } from '../providers'; import { fetchDataOptions } from '../providers';
import { enabledChains, type NetIdType, type SubdomainMap } from '../networkConfig'; import { TornadoConfig, type NetIdType, type SubdomainMap } from '../networkConfig';
import { RelayerParams, MIN_STAKE_BALANCE } from '../relayerClient'; import { RelayerParams, MIN_STAKE_BALANCE } from '../relayerClient';
import type { TovarishClient } from '../tovarishClient'; import type { TovarishClient } from '../tovarishClient';
@@ -131,7 +130,6 @@ export class BaseEventsService<EventType extends MinimalEvents> {
/* eslint-enable @typescript-eslint/no-unused-vars */ /* eslint-enable @typescript-eslint/no-unused-vars */
async formatEvents(events: EventLog[]): Promise<EventType[]> { async formatEvents(events: EventLog[]): Promise<EventType[]> {
// eslint-disable-next-line no-return-await
return await new Promise((resolve) => resolve(events as unknown as EventType[])); return await new Promise((resolve) => resolve(events as unknown as EventType[]));
} }
@@ -440,17 +438,13 @@ export class BaseTornadoService extends BaseEventsService<DepositsEvents | Withd
} }
export interface BaseMultiTornadoServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> { export interface BaseMultiTornadoServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
instances: { instances: Record<string, DepositType>;
[key in string]: DepositType;
};
optionalTree?: boolean; optionalTree?: boolean;
merkleTreeService?: MerkleTreeService; merkleTreeService?: MerkleTreeService;
} }
export class BaseMultiTornadoService extends BaseEventsService<MultiDepositsEvents | MultiWithdrawalsEvents> { export class BaseMultiTornadoService extends BaseEventsService<MultiDepositsEvents | MultiWithdrawalsEvents> {
instances: { instances: Record<string, DepositType>;
[key in string]: DepositType;
};
optionalTree?: boolean; optionalTree?: boolean;
merkleTreeService?: MerkleTreeService; merkleTreeService?: MerkleTreeService;
@@ -717,7 +711,7 @@ export class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesE
const abiCoder = AbiCoder.defaultAbiCoder(); const abiCoder = AbiCoder.defaultAbiCoder();
export const proposalState: { [key: string]: string } = { export const proposalState: Record<string, string> = {
0: 'Pending', 0: 'Pending',
1: 'Active', 1: 'Active',
2: 'Defeated', 2: 'Defeated',
@@ -821,13 +815,13 @@ export interface GovernanceVotes extends GovernanceVotedEvents {
export interface BaseGovernanceServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> { export interface BaseGovernanceServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
Governance: Governance; Governance: Governance;
Aggregator: Aggregator; Aggregator: TovarishAggregator;
ReverseRecords: ReverseRecords; ReverseRecords: ReverseRecords;
} }
export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents> { export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents> {
Governance: Governance; Governance: Governance;
Aggregator: Aggregator; Aggregator: TovarishAggregator;
ReverseRecords: ReverseRecords; ReverseRecords: ReverseRecords;
batchTransactionService: BatchTransactionService; batchTransactionService: BatchTransactionService;
@@ -955,7 +949,7 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
const [QUORUM_VOTES, proposalStatus, proposerNameRecords] = await Promise.all([ const [QUORUM_VOTES, proposalStatus, proposerNameRecords] = await Promise.all([
this.Governance.QUORUM_VOTES(), this.Governance.QUORUM_VOTES(),
this.Aggregator.getAllProposals(this.Governance.target), this.Aggregator.getAllProposals(),
this.ReverseRecords.getNames(allProposers), this.ReverseRecords.getNames(allProposers),
]); ]);
@@ -966,7 +960,7 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
} }
return acc; return acc;
}, },
{} as { [key: string]: string }, {} as Record<string, string>,
); );
return proposalEvents.map((event, index) => { return proposalEvents.map((event, index) => {
@@ -1018,7 +1012,7 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
} }
return acc; return acc;
}, },
{} as { [key: string]: string }, {} as Record<string, string>,
); );
const votes = votedEvents.map((event) => { const votes = votedEvents.map((event) => {
@@ -1066,7 +1060,7 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
}); });
const [balances, uniqNameRecords] = await Promise.all([ const [balances, uniqNameRecords] = await Promise.all([
this.Aggregator.getGovernanceBalances(this.Governance.target, uniq), this.Aggregator.getGovernanceBalances(uniq),
this.ReverseRecords.getNames(uniq), this.ReverseRecords.getNames(uniq),
]); ]);
@@ -1077,7 +1071,7 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
} }
return acc; return acc;
}, },
{} as { [key: string]: string }, {} as Record<string, string>,
); );
return { return {
@@ -1091,28 +1085,6 @@ export class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents
} }
} }
export async function getTovarishNetworks(registryService: BaseRegistryService, relayers: CachedRelayerInfo[]) {
await Promise.all(
relayers
.filter((r) => r.tovarishHost)
.map(async (relayer) => {
try {
relayer.tovarishNetworks = await fetchData(relayer.tovarishHost as string, {
...registryService.fetchDataOptions,
headers: {
'Content-Type': 'application/json',
},
timeout: 30000,
maxRetry: registryService.fetchDataOptions?.torPort ? 2 : 0,
});
} catch {
// Ignore error and disable relayer
relayer.tovarishNetworks = [];
}
}),
);
}
/** /**
* Essential params: * Essential params:
* ensName, relayerAddress, hostnames * ensName, relayerAddress, hostnames
@@ -1120,55 +1092,26 @@ export async function getTovarishNetworks(registryService: BaseRegistryService,
*/ */
export interface CachedRelayerInfo extends RelayerParams { export interface CachedRelayerInfo extends RelayerParams {
isRegistered?: boolean; isRegistered?: boolean;
registeredAddress?: string; isPrior?: boolean;
stakeBalance?: string; stakeBalance?: string;
hostnames: SubdomainMap; hostnames: SubdomainMap;
tovarishHost?: string; tovarishHost?: string;
tovarishNetworks?: number[]; tovarishNetworks?: number[];
} }
/**
* Static relayer provided by tornadowithdraw.eth
* This relayer isn't compatible with the current UI (tornadocash.eth) and only works as experimental mode
* Once DAO approves changes to UI to support new Tovarish Relayer software register relayer and remove static list
*/
const staticRelayers: CachedRelayerInfo[] = [
{
ensName: 'tornadowithdraw.eth',
relayerAddress: '0x40c3d1656a26C9266f4A10fed0D87EFf79F54E64',
hostnames: {},
tovarishHost: 'tornadowithdraw.com',
tovarishNetworks: enabledChains,
},
{
ensName: 'rpc.tornadowithdraw.eth',
relayerAddress: '0xFF787B7A5cd8a88508361E3B7bcE791Aa2796526',
hostnames: {},
tovarishHost: 'tornadocash-rpc.com',
tovarishNetworks: enabledChains,
},
];
export interface CachedRelayers {
lastBlock: number;
timestamp: number;
relayers: CachedRelayerInfo[];
fromCache?: boolean;
}
export interface BaseRegistryServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> { export interface BaseRegistryServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
tornadoConfig: TornadoConfig;
RelayerRegistry: RelayerRegistry; RelayerRegistry: RelayerRegistry;
Aggregator: Aggregator; Aggregator: TovarishAggregator;
relayerEnsSubdomains: SubdomainMap;
} }
export class BaseRegistryService extends BaseEventsService<AllRelayerRegistryEvents> { export class BaseRegistryService extends BaseEventsService<AllRelayerRegistryEvents> {
Aggregator: Aggregator; tornadoConfig: TornadoConfig;
relayerEnsSubdomains: SubdomainMap; Aggregator: TovarishAggregator;
updateInterval: number; updateInterval: number;
constructor(serviceConstructor: BaseRegistryServiceConstructor) { constructor(serviceConstructor: BaseRegistryServiceConstructor) {
const { RelayerRegistry: contract, Aggregator, relayerEnsSubdomains } = serviceConstructor; const { RelayerRegistry: contract, tornadoConfig, Aggregator } = serviceConstructor;
super({ super({
...serviceConstructor, ...serviceConstructor,
@@ -1176,8 +1119,8 @@ export class BaseRegistryService extends BaseEventsService<AllRelayerRegistryEve
type: '*', type: '*',
}); });
this.tornadoConfig = tornadoConfig;
this.Aggregator = Aggregator; this.Aggregator = Aggregator;
this.relayerEnsSubdomains = relayerEnsSubdomains;
this.updateInterval = 86400; this.updateInterval = 86400;
} }
@@ -1254,69 +1197,38 @@ export class BaseRegistryService extends BaseEventsService<AllRelayerRegistryEve
]; ];
} }
/** async getLatestRelayers(knownRelayers?: string[]): Promise<CachedRelayerInfo[]> {
* Get saved or cached relayers const newRelayers: string[] = [];
*/
async getRelayersFromDB(): Promise<CachedRelayers> {
return {
lastBlock: 0,
timestamp: 0,
relayers: [],
};
}
/** if (knownRelayers?.length) {
* Relayers from remote cache (Either from local cache, CDN, or from IPFS) const { events: allEvents } = await this.updateEvents();
*/
async getRelayersFromCache(): Promise<CachedRelayers> {
return {
lastBlock: 0,
timestamp: 0,
relayers: [],
fromCache: true,
};
}
async getSavedRelayers(): Promise<CachedRelayers> {
let cachedRelayers = await this.getRelayersFromDB();
if (!cachedRelayers || !cachedRelayers.relayers.length) {
cachedRelayers = await this.getRelayersFromCache();
}
return cachedRelayers;
}
async getLatestRelayers(): Promise<CachedRelayers> {
const { events: allEvents, lastBlock } = await this.updateEvents();
const events = allEvents.filter((e) => e.event === 'RelayerRegistered') as RelayerRegisteredEvents[]; const events = allEvents.filter((e) => e.event === 'RelayerRegistered') as RelayerRegisteredEvents[];
const subdomains = Object.values(this.relayerEnsSubdomains); for (const { ensName } of events) {
if (!newRelayers.includes(ensName) && !knownRelayers?.includes(ensName)) {
const registerSet = new Set(); newRelayers.push(ensName);
}
const uniqueRegisters = events.filter(({ ensName }) => { }
if (!registerSet.has(ensName)) {
registerSet.add(ensName);
return true;
} }
return false;
});
const relayerNameHashes = uniqueRegisters.map((r) => namehash(r.ensName)); const [chains, relayersData] = await Promise.all([
this.Aggregator.getChainIds.staticCall(),
const [relayersData, timestamp] = await Promise.all([ this.Aggregator.relayersData.staticCall(newRelayers),
this.Aggregator.relayersData.staticCall(relayerNameHashes, subdomains.concat('tovarish-relayer')),
this.provider.getBlock(lastBlock).then((b) => Number(b?.timestamp)),
]); ]);
const relayers = relayersData const relayers = relayersData
.map(({ owner, balance: stakeBalance, records, isRegistered }, index) => { .map(
const { ensName, relayerAddress } = uniqueRegisters[index]; ({
ensName,
let tovarishHost = undefined; owner,
balance: stakeBalance,
isRegistered,
isPrior,
tovarishHost,
tovarishChains,
records,
}) => {
const hostnames = records.reduce((acc, record, recordIndex) => { const hostnames = records.reduce((acc, record, recordIndex) => {
if (record) { if (record) {
// tovarish-relayer.relayer.eth // tovarish-relayer.relayer.eth
@@ -1325,70 +1237,60 @@ export class BaseRegistryService extends BaseEventsService<AllRelayerRegistryEve
return acc; return acc;
} }
acc[Number(Object.keys(this.relayerEnsSubdomains)[recordIndex])] = record; acc[Number(chains[recordIndex])] = record;
} }
return acc; return acc;
}, {} as SubdomainMap); }, {} as SubdomainMap);
const hasMinBalance = stakeBalance >= MIN_STAKE_BALANCE; const hasMinBalance = stakeBalance >= MIN_STAKE_BALANCE;
const preCondition = Object.keys(hostnames).length && isRegistered && hasMinBalance; const tovarishNetworks = [
...new Set(
tovarishChains
.split(',')
.map((c) => Number(c))
.filter((c) => c && this.tornadoConfig.chains.includes(c)),
),
];
const preCondition =
(isRegistered && hasMinBalance && Object.keys(hostnames).length) ||
(tovarishHost.length && tovarishNetworks.length);
if (preCondition) { if (preCondition) {
return { return {
ensName, ensName,
relayerAddress: owner, relayerAddress: owner,
registeredAddress: owner !== relayerAddress ? relayerAddress : undefined, isPrior,
isRegistered, isRegistered,
stakeBalance: formatEther(stakeBalance), stakeBalance: formatEther(stakeBalance),
hostnames, hostnames,
tovarishHost, tovarishHost,
tovarishNetworks,
} as CachedRelayerInfo; } as CachedRelayerInfo;
} }
}) },
)
.filter((r) => r) as CachedRelayerInfo[]; .filter((r) => r) as CachedRelayerInfo[];
await getTovarishNetworks(this, relayers); const sortedRelayers = relayers.sort((a, b) => {
// Scoring => isTovarishRelayer => hasMoreStakedBalance
// When it is tovarish relayer, it will compare with staked balance as well
const getPriorityScore = (i: CachedRelayerInfo) => (i.tovarishHost?.length || 0) + (i.isPrior ? 1 : 0);
const allRelayers = [...staticRelayers, ...relayers]; const [aScore, bScore] = [getPriorityScore(a), getPriorityScore(b)];
const tovarishRelayers = allRelayers.filter((r) => r.tovarishHost);
const classicRelayers = allRelayers.filter((r) => !r.tovarishHost);
return { if (aScore === bScore) {
lastBlock, // Sort by staked balance
timestamp, const [aBalance, bBalance] = [Number(a.stakeBalance || 0), Number(b.stakeBalance || 0)];
relayers: [...tovarishRelayers, ...classicRelayers],
}; return bBalance - aBalance;
} }
/** return bScore - aScore;
* Handle saving relayers });
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async saveRelayers({ lastBlock, timestamp, relayers }: CachedRelayers) {}
/** return sortedRelayers;
* Get cached or latest relayer and save to local
*/
async updateRelayers(): Promise<CachedRelayers> {
// eslint-disable-next-line prefer-const
let { lastBlock, timestamp, relayers, fromCache } = await this.getSavedRelayers();
let shouldSave = fromCache ?? false;
if (!relayers.length || timestamp + this.updateInterval < Math.floor(Date.now() / 1000)) {
console.log('\nUpdating relayers from registry\n');
({ lastBlock, timestamp, relayers } = await this.getLatestRelayers());
shouldSave = true;
}
if (shouldSave) {
await this.saveRelayers({ lastBlock, timestamp, relayers });
}
return { lastBlock, timestamp, relayers };
} }
} }

View File

@@ -1,8 +1,6 @@
import { downloadZip } from '../zip'; import { downloadZip } from '../zip';
import { IndexedDB } from '../idb'; import { IndexedDB } from '../idb';
import { bytesToBase64, digest } from '../utils';
import { fetchData } from '../providers';
import { import {
BaseTornadoService, BaseTornadoService,
BaseTornadoServiceConstructor, BaseTornadoServiceConstructor,
@@ -16,7 +14,6 @@ import {
BaseRegistryServiceConstructor, BaseRegistryServiceConstructor,
BaseRevenueService, BaseRevenueService,
BaseRevenueServiceConstructor, BaseRevenueServiceConstructor,
CachedRelayers,
BaseMultiTornadoService, BaseMultiTornadoService,
BaseMultiTornadoServiceConstructor, BaseMultiTornadoServiceConstructor,
} from './base'; } from './base';
@@ -403,7 +400,6 @@ export class DBRegistryService extends BaseRegistryService {
idb: IndexedDB; idb: IndexedDB;
zipDigest?: string; zipDigest?: string;
relayerJsonDigest?: string;
constructor(params: DBRegistryServiceConstructor) { constructor(params: DBRegistryServiceConstructor) {
super(params); super(params);
@@ -439,78 +435,6 @@ export class DBRegistryService extends BaseRegistryService {
lastBlock, lastBlock,
}); });
} }
async getRelayersFromDB(): Promise<CachedRelayers> {
try {
const allCachedRelayers = await this.idb.getAll<CachedRelayers[]>({
storeName: `relayers_${this.netId}`,
});
if (!allCachedRelayers?.length) {
return {
lastBlock: 0,
timestamp: 0,
relayers: [],
};
}
return allCachedRelayers.slice(-1)[0];
} catch (err) {
console.log('Method getRelayersFromDB has error');
console.log(err);
return {
lastBlock: 0,
timestamp: 0,
relayers: [],
};
}
}
async getRelayersFromCache(): Promise<CachedRelayers> {
const url = `${this.staticUrl}/relayers.json`;
try {
const resp = await fetchData(url, {
method: 'GET',
returnResponse: true,
});
const data = new Uint8Array(await resp.arrayBuffer());
if (this.relayerJsonDigest) {
const hash = 'sha384-' + bytesToBase64(await digest(data));
if (hash !== this.relayerJsonDigest) {
const errMsg = `Invalid digest hash for ${url}, wants ${this.relayerJsonDigest} has ${hash}`;
throw new Error(errMsg);
}
}
return JSON.parse(new TextDecoder().decode(data)) as CachedRelayers;
} catch (err) {
console.log('Method getRelayersFromCache has error');
console.log(err);
return {
lastBlock: 0,
timestamp: 0,
relayers: [],
};
}
}
async saveRelayers(cachedRelayers: CachedRelayers): Promise<void> {
try {
await this.idb.putItem({
data: cachedRelayers,
storeName: `relayers_${this.netId}`,
});
} catch (err) {
console.log('Method saveRelayers has error');
console.log(err);
}
}
} }
export interface DBRevenueServiceConstructor extends BaseRevenueServiceConstructor { export interface DBRevenueServiceConstructor extends BaseRevenueServiceConstructor {

View File

@@ -17,7 +17,7 @@ const DUMMY_WITHDRAW_DATA =
export function convertETHToTokenAmount( export function convertETHToTokenAmount(
amountInWei: BigNumberish, amountInWei: BigNumberish,
tokenPriceInWei: BigNumberish, tokenPriceInWei: BigNumberish,
tokenDecimals: number = 18, tokenDecimals = 18,
): bigint { ): bigint {
const tokenDecimalsMultiplier = BigInt(10 ** Number(tokenDecimals)); const tokenDecimalsMultiplier = BigInt(10 ** Number(tokenDecimals));
return (BigInt(amountInWei) * tokenDecimalsMultiplier) / BigInt(tokenPriceInWei); return (BigInt(amountInWei) * tokenDecimalsMultiplier) / BigInt(tokenPriceInWei);

View File

@@ -2,7 +2,7 @@ import { isAddress } from 'ethers';
import { NetId, NetIdType } from './networkConfig'; import { NetId, NetIdType } from './networkConfig';
// https://dev.gas.zip/gas/chain-support/inbound // https://dev.gas.zip/gas/chain-support/inbound
export const gasZipInbounds: { [key in NetIdType]: string } = { export const gasZipInbounds: Record<NetIdType, string> = {
[NetId.MAINNET]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604', [NetId.MAINNET]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.BSC]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604', [NetId.BSC]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.POLYGON]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604', [NetId.POLYGON]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
@@ -15,7 +15,7 @@ export const gasZipInbounds: { [key in NetIdType]: string } = {
}; };
// https://dev.gas.zip/gas/chain-support/outbound // https://dev.gas.zip/gas/chain-support/outbound
export const gasZipID: { [key in NetIdType]: number } = { export const gasZipID: Record<NetIdType, number> = {
[NetId.MAINNET]: 255, [NetId.MAINNET]: 255,
[NetId.BSC]: 14, [NetId.BSC]: 14,
[NetId.POLYGON]: 17, [NetId.POLYGON]: 17,

View File

@@ -49,9 +49,7 @@ export interface queryGraphParams {
graphApi: string; graphApi: string;
subgraphName: string; subgraphName: string;
query: string; query: string;
variables?: { variables?: Record<string, string | number>;
[key: string]: string | number;
};
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
} }
@@ -64,7 +62,8 @@ export async function queryGraph<T>({
}: queryGraphParams): Promise<T> { }: queryGraphParams): Promise<T> {
const graphUrl = `${graphApi}/subgraphs/name/${subgraphName}`; const graphUrl = `${graphApi}/subgraphs/name/${subgraphName}`;
const { data, errors } = await fetchData(graphUrl, { // eslint-disable-next-line @typescript-eslint/no-explicit-any
const { data, errors } = await fetchData<{ data: T & { _meta: any }; errors: any }>(graphUrl, {
...fetchDataOptions, ...fetchDataOptions,
method: 'POST', method: 'POST',
headers: { headers: {
@@ -270,7 +269,6 @@ export async function getAllRegisters({
const events = []; const events = [];
let lastSyncBlock = fromBlock; let lastSyncBlock = fromBlock;
// eslint-disable-next-line no-constant-condition
while (true) { while (true) {
let { let {
relayers: result, relayers: result,
@@ -406,7 +404,6 @@ export async function getAllDeposits({
const events = []; const events = [];
let lastSyncBlock = fromBlock; let lastSyncBlock = fromBlock;
// eslint-disable-next-line no-constant-condition
while (true) { while (true) {
let { let {
deposits: result, deposits: result,
@@ -552,7 +549,6 @@ export async function getAllWithdrawals({
const events = []; const events = [];
let lastSyncBlock = fromBlock; let lastSyncBlock = fromBlock;
// eslint-disable-next-line no-constant-condition
while (true) { while (true) {
let { let {
withdrawals: result, withdrawals: result,
@@ -756,7 +752,6 @@ export async function getAllGraphEchoEvents({
const events = []; const events = [];
let lastSyncBlock = fromBlock; let lastSyncBlock = fromBlock;
// eslint-disable-next-line no-constant-condition
while (true) { while (true) {
let { let {
noteAccounts: result, noteAccounts: result,
@@ -888,7 +883,6 @@ export async function getAllEncryptedNotes({
const events = []; const events = [];
let lastSyncBlock = fromBlock; let lastSyncBlock = fromBlock;
// eslint-disable-next-line no-constant-condition
while (true) { while (true) {
let { let {
encryptedNotes: result, encryptedNotes: result,
@@ -1046,7 +1040,6 @@ export async function getAllGovernanceEvents({
let lastSyncBlock = fromBlock; let lastSyncBlock = fromBlock;
// eslint-disable-next-line no-constant-condition
while (true) { while (true) {
const { const {
proposals, proposals,

View File

@@ -1,6 +1,13 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any, import/no-duplicates */
import { openDB, deleteDB, OpenDBCallbacks, IDBPDatabase } from 'idb'; import type * as idb from 'idb';
import { getConfig, NetIdType } from './networkConfig'; import type { OpenDBCallbacks, IDBPDatabase } from 'idb';
import type { NetIdType, TornadoConfig } from './networkConfig';
declare global {
interface Window {
idb: typeof idb;
}
}
export const INDEX_DB_ERROR = 'A mutation operation was attempted on a database that did not allow mutations.'; export const INDEX_DB_ERROR = 'A mutation operation was attempted on a database that did not allow mutations.';
@@ -64,7 +71,7 @@ export class IndexedDB {
return; return;
} }
this.db = await openDB(this.dbName, this.dbVersion, this.options); this.db = await window?.idb?.openDB(this.dbName, this.dbVersion, this.options);
this.db.addEventListener('onupgradeneeded', async () => { this.db.addEventListener('onupgradeneeded', async () => {
await this._removeExist(); await this._removeExist();
}); });
@@ -89,7 +96,7 @@ export class IndexedDB {
} }
async _removeExist() { async _removeExist() {
await deleteDB(this.dbName); await window?.idb?.deleteDB(this.dbName);
this.dbExists = false; this.dbExists = false;
await this.initDB(); await this.initDB();
@@ -314,10 +321,10 @@ export class IndexedDB {
/** /**
* Should check if DB is initialized well * Should check if DB is initialized well
*/ */
export async function getIndexedDB(netId?: NetIdType) { export async function getIndexedDB(netId?: NetIdType, tornadoConfig?: TornadoConfig) {
// key-value db for settings // key-value db for settings
if (!netId) { if (!netId || !tornadoConfig) {
const idb = new IndexedDB({ dbName: 'tornado-core' }); const idb = new IndexedDB({ dbName: 'tornado-scripts' });
await idb.initDB(); await idb.initDB();
return idb; return idb;
} }
@@ -363,7 +370,7 @@ export async function getIndexedDB(netId?: NetIdType) {
}, },
]; ];
const { tokens, nativeCurrency, registryContract, governanceContract } = getConfig(netId); const { tokens, nativeCurrency, registryContract, governanceContract } = tornadoConfig.getConfig(netId);
const stores = [...defaultState]; const stores = [...defaultState];
@@ -380,17 +387,6 @@ export async function getIndexedDB(netId?: NetIdType) {
], ],
}); });
stores.push({
name: `relayers_${netId}`,
keyPath: 'timestamp',
indexes: [
{
name: 'timestamp',
unique: true,
},
],
});
stores.push({ stores.push({
name: `revenue_${netId}`, name: `revenue_${netId}`,
keyPath: 'timestamp', keyPath: 'timestamp',

View File

@@ -1,14 +1,37 @@
import { fetchData } from './providers'; import { fetchData, fetchDataOptions } from './providers';
export interface IPResult { export interface IPResult {
ip: string; ip: string;
iso?: string; iso?: string;
country?: string;
country_iso?: string;
tor?: boolean; tor?: boolean;
} }
export async function fetchIp(ipEcho: string) { export function fetchIp(ipEcho: string, fetchOptions?: fetchDataOptions) {
return (await fetchData(ipEcho, { return fetchData<IPResult>(ipEcho, {
...(fetchOptions || {}),
method: 'GET', method: 'GET',
timeout: 30000, timeout: 30000,
})) as IPResult; });
}
// 🖕
export interface IPResultFuck {
YourFuckingIPAddress: string;
YourFuckingLocation: string;
YourFuckingHostname: string;
YourFuckingISP: string;
YourFuckingTorExit: boolean;
YourFuckingCity?: string;
YourFuckingCountry: string;
YourFuckingCountryCode: string;
}
export function fetchFuckingIp(ipFuck = 'https://myip.wtf/json', fetchOptions?: fetchDataOptions) {
return fetchData<IPResultFuck>(ipFuck, {
...(fetchOptions || {}),
method: 'GET',
timeout: 30000,
});
} }

View File

@@ -1,6 +1,6 @@
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 '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';
import type { DepositType } from './deposits'; import type { DepositType } from './deposits';

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
import { ERC20Permit, ERC20Mock, TORN } from '@tornado/contracts'; import { ERC20Permit, ERC20Mock, TORN } from 'tornado-contracts';
import { MaxUint256, Provider, Signature, Signer, TypedDataField } from 'ethers'; import { MaxUint256, Provider, Signature, Signer, TypedDataField } from 'ethers';
export interface PermitValue { export interface PermitValue {
@@ -22,9 +22,7 @@ export const permit2Address = '0x000000000022D473030F116dDEE9F6B43aC78BA3';
*/ */
export interface Witness { export interface Witness {
witnessTypeName: string; witnessTypeName: string;
witnessType: { witnessType: Record<string, TypedDataField[]>;
[key: string]: TypedDataField[];
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
witness: any; witness: any;
} }

View File

@@ -1,6 +1,4 @@
import type { EventEmitter } from 'stream'; import type { EventEmitter } from 'stream';
import type { RequestOptions } from 'http';
import crossFetch from 'cross-fetch';
import { import {
FetchRequest, FetchRequest,
JsonRpcApiProvider, JsonRpcApiProvider,
@@ -20,10 +18,13 @@ import {
EnsPlugin, EnsPlugin,
GasCostPlugin, GasCostPlugin,
FetchCancelSignal, FetchCancelSignal,
resolveProperties,
TransactionLike,
FetchUrlFeeDataNetworkPlugin,
FeeData,
} from 'ethers'; } from 'ethers';
import type { RequestInfo, RequestInit, Response, HeadersInit } from 'node-fetch'; import type { Dispatcher, RequestInit, fetch as undiciFetch } from 'undici-types';
// Temporary workaround until @types/node-fetch is compatible with @types/node
import type { AbortSignal as FetchAbortSignal } from 'node-fetch/externals';
import { isNode, sleep } from './utils'; import { isNode, sleep } from './utils';
import type { Config, NetIdType } from './networkConfig'; import type { Config, NetIdType } from './networkConfig';
@@ -36,73 +37,34 @@ declare global {
// Update this for every Tor Browser release // Update this for every Tor Browser release
export const defaultUserAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0'; export const defaultUserAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0';
export type nodeFetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>; export type DispatcherFunc = (retry?: number) => Dispatcher;
export type fetchDataOptions = RequestInit & { export interface fetchDataOptions extends Omit<RequestInit, 'headers'> {
/**
* Overriding RequestInit params
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
headers?: HeadersInit | any; headers?: HeadersInit | any;
/**
* Expanding RequestInit params
*/
maxRetry?: number; maxRetry?: number;
retryOn?: number; retryOn?: number;
userAgent?: string; userAgent?: string;
timeout?: number; timeout?: number;
proxy?: string;
torPort?: number;
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
debug?: Function; debug?: Function;
returnResponse?: boolean; returnResponse?: boolean;
cancelSignal?: FetchCancelSignal; cancelSignal?: FetchCancelSignal;
}; dispatcherFunc?: DispatcherFunc;
export type NodeAgent = RequestOptions['agent'] | ((parsedUrl: URL) => RequestOptions['agent']);
export function getHttpAgent({
fetchUrl,
proxyUrl,
torPort,
retry,
}: {
fetchUrl: string;
proxyUrl?: string;
torPort?: number;
retry: number;
}): NodeAgent | undefined {
/* eslint-disable @typescript-eslint/no-require-imports */
const { HttpProxyAgent } = require('http-proxy-agent');
const { HttpsProxyAgent } = require('https-proxy-agent');
const { SocksProxyAgent } = require('socks-proxy-agent');
/* eslint-enable @typescript-eslint/no-require-imports */
if (torPort) {
return new SocksProxyAgent(`socks5h://tor${retry}@127.0.0.1:${torPort}`);
}
if (!proxyUrl) {
return;
}
const isHttps = fetchUrl.includes('https://');
if (proxyUrl.includes('socks://') || proxyUrl.includes('socks4://') || proxyUrl.includes('socks5://')) {
return new SocksProxyAgent(proxyUrl);
}
if (proxyUrl.includes('http://') || proxyUrl.includes('https://')) {
if (isHttps) {
return new HttpsProxyAgent(proxyUrl);
}
return new HttpProxyAgent(proxyUrl);
}
} }
export async function fetchData(url: string, options: fetchDataOptions = {}) { export async function fetchData<T>(url: string, options: fetchDataOptions = {}): Promise<T> {
const MAX_RETRY = options.maxRetry ?? 3; const MAX_RETRY = options.maxRetry ?? 3;
const RETRY_ON = options.retryOn ?? 500; const RETRY_ON = options.retryOn ?? 500;
const userAgent = options.userAgent ?? defaultUserAgent; const userAgent = options.userAgent ?? defaultUserAgent;
const fetch = ((globalThis as unknown as { useGlobalFetch?: boolean }).useGlobalFetch
? globalThis.fetch
: crossFetch) as unknown as nodeFetch;
let retry = 0; let retry = 0;
let errorObject; let errorObject;
@@ -122,14 +84,17 @@ export async function fetchData(url: string, options: fetchDataOptions = {}) {
options.headers['User-Agent'] = userAgent; options.headers['User-Agent'] = userAgent;
} }
if (typeof globalThis.fetch !== 'function') {
throw new Error('Fetch API is not available, use latest browser or nodejs installation!');
}
while (retry < MAX_RETRY + 1) { while (retry < MAX_RETRY + 1) {
let timeout; let timeout;
if (!options.signal && options.timeout) { if (!options.signal && options.timeout) {
const controller = new AbortController(); const controller = new AbortController();
// Temporary workaround until @types/node-fetch is compatible with @types/node options.signal = controller.signal;
options.signal = controller.signal as FetchAbortSignal;
// Define timeout in seconds // Define timeout in seconds
timeout = setTimeout(() => { timeout = setTimeout(() => {
@@ -149,16 +114,7 @@ export async function fetchData(url: string, options: fetchDataOptions = {}) {
} }
} }
if (!options.agent && isNode && (options.proxy || options.torPort)) { if (typeof options.debug === 'function') {
options.agent = getHttpAgent({
fetchUrl: url,
proxyUrl: options.proxy,
torPort: options.torPort,
retry,
});
}
if (options.debug && typeof options.debug === 'function') {
options.debug('request', { options.debug('request', {
url, url,
retry, retry,
@@ -168,13 +124,11 @@ export async function fetchData(url: string, options: fetchDataOptions = {}) {
} }
try { try {
const resp = await fetch(url, { const dispatcher = options.dispatcherFunc ? options.dispatcherFunc(retry) : options.dispatcher;
method: options.method,
headers: options.headers, const resp = await (globalThis.fetch as unknown as typeof undiciFetch)(url, {
body: options.body, ...options,
redirect: options.redirect, dispatcher,
signal: options.signal,
agent: options.agent,
}); });
if (options.debug && typeof options.debug === 'function') { if (options.debug && typeof options.debug === 'function') {
@@ -187,23 +141,23 @@ export async function fetchData(url: string, options: fetchDataOptions = {}) {
} }
if (options.returnResponse) { if (options.returnResponse) {
return resp; return resp as T;
} }
const contentType = resp.headers.get('content-type'); const contentType = resp.headers.get('content-type');
// If server returns JSON object, parse it and return as an object // If server returns JSON object, parse it and return as an object
if (contentType?.includes('application/json')) { if (contentType?.includes('application/json')) {
return await resp.json(); return (await resp.json()) as T;
} }
// Else if the server returns text parse it as a string // Else if the server returns text parse it as a string
if (contentType?.includes('text')) { if (contentType?.includes('text')) {
return await resp.text(); return (await resp.text()) as T;
} }
// Return as a response object https://developer.mozilla.org/en-US/docs/Web/API/Response // Return as a response object https://developer.mozilla.org/en-US/docs/Web/API/Response
return resp; return resp as T;
} catch (error) { } catch (error) {
if (timeout) { if (timeout) {
clearTimeout(timeout); clearTimeout(timeout);
@@ -242,9 +196,9 @@ export const fetchGetUrlFunc =
returnResponse: true, returnResponse: true,
}; };
const resp = await fetchData(req.url, init); const resp = await fetchData<Response>(req.url, init);
const headers = {} as { [key in string]: any }; const headers = {} as Record<string, any>;
resp.headers.forEach((value: any, key: string) => { resp.headers.forEach((value: any, key: string) => {
headers[key.toLowerCase()] = value; headers[key.toLowerCase()] = value;
}); });
@@ -267,20 +221,36 @@ export type getProviderOptions = fetchDataOptions & {
pollingInterval?: number; pollingInterval?: number;
}; };
export const FeeDataNetworkPluginName = new FetchUrlFeeDataNetworkPlugin(
'',
() => new Promise((resolve) => resolve(new FeeData())),
).name;
export async function getProvider(rpcUrl: string, fetchOptions?: getProviderOptions): Promise<JsonRpcProvider> { export async function getProvider(rpcUrl: string, fetchOptions?: getProviderOptions): Promise<JsonRpcProvider> {
// Use our own fetchGetUrlFunc to support proxies and retries
const fetchReq = new FetchRequest(rpcUrl); const fetchReq = new FetchRequest(rpcUrl);
fetchReq.getUrlFunc = fetchGetUrlFunc(fetchOptions); fetchReq.getUrlFunc = fetchGetUrlFunc(fetchOptions);
const staticNetwork = await new JsonRpcProvider(fetchReq).getNetwork(); const fetchedNetwork = await new JsonRpcProvider(fetchReq).getNetwork();
const chainId = Number(staticNetwork.chainId); // Audit if we are connected to right network
const chainId = Number(fetchedNetwork.chainId);
if (fetchOptions?.netId && fetchOptions.netId !== chainId) { if (fetchOptions?.netId && fetchOptions.netId !== chainId) {
const errMsg = `Wrong network for ${rpcUrl}, wants ${fetchOptions.netId} got ${chainId}`; const errMsg = `Wrong network for ${rpcUrl}, wants ${fetchOptions.netId} got ${chainId}`;
throw new Error(errMsg); throw new Error(errMsg);
} }
// Clone to new network to exclude polygon gas station plugin
const staticNetwork = new Network(fetchedNetwork.name, fetchedNetwork.chainId);
fetchedNetwork.plugins.forEach((plugin) => {
if (plugin.name !== FeeDataNetworkPluginName) {
staticNetwork.attachPlugin(plugin.clone());
}
});
return new JsonRpcProvider(fetchReq, staticNetwork, { return new JsonRpcProvider(fetchReq, staticNetwork, {
staticNetwork, staticNetwork,
pollingInterval: fetchOptions?.pollingInterval || 1000, pollingInterval: fetchOptions?.pollingInterval || 1000,
@@ -293,7 +263,7 @@ export function getProviderWithNetId(
config: Config, config: Config,
fetchOptions?: getProviderOptions, fetchOptions?: getProviderOptions,
): JsonRpcProvider { ): JsonRpcProvider {
const { networkName, reverseRecordsContract, pollInterval } = config; const { networkName, reverseRecordsContract, blockTime } = config;
const hasEns = Boolean(reverseRecordsContract); const hasEns = Boolean(reverseRecordsContract);
const fetchReq = new FetchRequest(rpcUrl); const fetchReq = new FetchRequest(rpcUrl);
@@ -306,7 +276,7 @@ export function getProviderWithNetId(
const provider = new JsonRpcProvider(fetchReq, staticNetwork, { const provider = new JsonRpcProvider(fetchReq, staticNetwork, {
staticNetwork, staticNetwork,
pollingInterval: fetchOptions?.pollingInterval || pollInterval * 1000, pollingInterval: fetchOptions?.pollingInterval || blockTime * 1000,
}); });
return provider; return provider;
@@ -325,11 +295,16 @@ export const populateTransaction = async (
throw new Error(errMsg); throw new Error(errMsg);
} }
const [feeData, nonce] = await Promise.all([ const [chainId, feeData, nonce] = await Promise.all([
tx.chainId || tx.chainId === 0n ? undefined : provider.getNetwork().then((n) => Number(n.chainId)),
tx.maxFeePerGas || tx.gasPrice ? undefined : provider.getFeeData(), tx.maxFeePerGas || tx.gasPrice ? undefined : provider.getFeeData(),
tx.nonce ? undefined : provider.getTransactionCount(signer.address, 'pending'), tx.nonce || tx.nonce === 0 ? undefined : provider.getTransactionCount(signer.address, 'pending'),
]); ]);
if (chainId) {
tx.chainId = chainId;
}
if (feeData) { if (feeData) {
// EIP-1559 // EIP-1559
if (feeData.maxFeePerGas) { if (feeData.maxFeePerGas) {
@@ -350,7 +325,7 @@ export const populateTransaction = async (
} }
} }
if (nonce) { if (nonce || nonce === 0) {
tx.nonce = nonce; tx.nonce = nonce;
} }
@@ -373,7 +348,7 @@ export const populateTransaction = async (
} }
} }
return tx; return resolveProperties(tx);
}; };
export interface TornadoWalletOptions { export interface TornadoWalletOptions {
@@ -414,8 +389,7 @@ export class TornadoWallet extends Wallet {
async populateTransaction(tx: TransactionRequest) { async populateTransaction(tx: TransactionRequest) {
const txObject = await populateTransaction(this, tx); const txObject = await populateTransaction(this, tx);
this.nonce = Number(txObject.nonce); this.nonce = Number(txObject.nonce);
return txObject as Promise<TransactionLike<string>>;
return super.populateTransaction(txObject);
} }
} }
@@ -443,8 +417,7 @@ export class TornadoVoidSigner extends VoidSigner {
async populateTransaction(tx: TransactionRequest) { async populateTransaction(tx: TransactionRequest) {
const txObject = await populateTransaction(this, tx); const txObject = await populateTransaction(this, tx);
this.nonce = Number(txObject.nonce); this.nonce = Number(txObject.nonce);
return txObject as Promise<TransactionLike<string>>;
return super.populateTransaction(txObject);
} }
} }

View File

@@ -1,6 +1,6 @@
import { getAddress, parseEther } from 'ethers'; import { getAddress, parseEther } from 'ethers';
import { sleep } from './utils'; import { sleep } from './utils';
import { NetId, NetIdType, Config } from './networkConfig'; import type { NetIdType, TornadoConfig } from './networkConfig';
import { fetchData, fetchDataOptions } from './providers'; import { fetchData, fetchDataOptions } from './providers';
import { ajv, jobsSchema, jobRequestSchema, getStatusSchema } from './schemas'; import { ajv, jobsSchema, jobRequestSchema, getStatusSchema } from './schemas';
import type { snarkProofs } from './websnark'; import type { snarkProofs } from './websnark';
@@ -28,9 +28,7 @@ export interface RelayerInfo extends RelayerParams {
instances: string[]; instances: string[];
stakeBalance?: string; stakeBalance?: string;
gasPrice?: number; gasPrice?: number;
ethPrices?: { ethPrices?: Record<string, string>;
[key in string]: string;
};
currentQueue: number; currentQueue: number;
tornadoServiceFee: number; tornadoServiceFee: number;
} }
@@ -45,24 +43,21 @@ export interface RelayerError {
export interface RelayerStatus { export interface RelayerStatus {
url: string; url: string;
rewardAccount: string; rewardAccount: string;
instances: { instances: Record<
[key in string]: { string,
instanceAddress: { {
[key in string]: string; instanceAddress: Record<string, string>;
};
tokenAddress?: string; tokenAddress?: string;
symbol: string; symbol: string;
decimals: number; decimals: number;
}; }
}; >;
gasPrices?: { gasPrices?: {
fast: number; fast: number;
additionalProperties?: number; additionalProperties?: number;
}; };
netId: NetIdType; netId: NetIdType;
ethPrices?: { ethPrices?: Record<string, string>;
[key in string]: string;
};
tornadoServiceFee: number; tornadoServiceFee: number;
latestBlock?: number; latestBlock?: number;
version: string; version: string;
@@ -149,13 +144,12 @@ export function getWeightRandom(weightsScores: bigint[], random: bigint) {
return Math.floor(Math.random() * weightsScores.length); return Math.floor(Math.random() * weightsScores.length);
} }
export interface RelayerInstanceList { export type RelayerInstanceList = Record<
[key: string]: { string,
instanceAddress: { {
[key: string]: string; instanceAddress: Record<string, string>;
}; }
}; >;
}
export function getSupportedInstances(instanceList: RelayerInstanceList) { export function getSupportedInstances(instanceList: RelayerInstanceList) {
const rawList = Object.values(instanceList) const rawList = Object.values(instanceList)
@@ -180,35 +174,31 @@ export function pickWeightedRandomRelayer(relayers: RelayerInfo[]) {
} }
export interface RelayerClientConstructor { export interface RelayerClientConstructor {
netId: NetIdType; tornadoConfig: TornadoConfig;
config: Config;
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
} }
export class RelayerClient { export class RelayerClient {
netId: NetIdType; tornadoConfig: TornadoConfig;
config: Config;
selectedRelayer?: RelayerInfo; selectedRelayer?: RelayerInfo;
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
tovarish: boolean; tovarish: boolean;
constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor) { constructor({ tornadoConfig, fetchDataOptions }: RelayerClientConstructor) {
this.netId = netId; this.tornadoConfig = tornadoConfig;
this.config = config;
this.fetchDataOptions = fetchDataOptions; this.fetchDataOptions = fetchDataOptions;
this.tovarish = false; this.tovarish = false;
} }
async askRelayerStatus({ async askRelayerStatus({
netId,
hostname, hostname,
url, url,
relayerAddress,
}: { }: {
netId: NetIdType;
hostname?: string; hostname?: string;
// optional url if entered manually // optional url if entered manually
url?: string; url?: string;
// relayerAddress from registry contract to prevent cheating
relayerAddress?: string;
}): Promise<RelayerStatus> { }): Promise<RelayerStatus> {
if (!url && hostname) { if (!url && hostname) {
url = `https://${!hostname.endsWith('/') ? hostname + '/' : hostname}`; url = `https://${!hostname.endsWith('/') ? hostname + '/' : hostname}`;
@@ -218,16 +208,18 @@ export class RelayerClient {
url = ''; url = '';
} }
const rawStatus = (await fetchData(`${url}status`, { const rawStatus = await fetchData<RelayerStatus>(`${url}status`, {
...this.fetchDataOptions, ...this.fetchDataOptions,
headers: { headers: {
'Content-Type': 'application/json, application/x-www-form-urlencoded', 'Content-Type': 'application/json, application/x-www-form-urlencoded',
}, },
timeout: 30000, timeout: 30000,
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0, maxRetry: this.fetchDataOptions?.dispatcher ? 2 : 0,
})) as object; });
const statusValidator = ajv.compile(getStatusSchema(this.netId, this.config, this.tovarish)); const config = this.tornadoConfig.getConfig(netId);
const statusValidator = ajv.compile(getStatusSchema(config, this.tovarish));
if (!statusValidator(rawStatus)) { if (!statusValidator(rawStatus)) {
throw new Error('Invalid status schema'); throw new Error('Invalid status schema');
@@ -242,19 +234,21 @@ export class RelayerClient {
throw new Error('Withdrawal queue is overloaded'); throw new Error('Withdrawal queue is overloaded');
} }
if (status.netId !== this.netId) { if (status.netId !== netId) {
throw new Error('This relayer serves a different network'); throw new Error('This relayer serves a different network');
} }
/**
if (relayerAddress && this.netId === NetId.MAINNET && status.rewardAccount !== relayerAddress) { if (relayerAddress && this.netId === NetId.MAINNET && status.rewardAccount !== relayerAddress) {
throw new Error('The Relayer reward address must match registered address'); throw new Error('The Relayer reward address must match registered address');
} }
**/
return status; return status;
} }
async filterRelayer(relayer: CachedRelayerInfo): Promise<RelayerInfo | RelayerError | undefined> { async filterRelayer(netId: NetIdType, relayer: CachedRelayerInfo): Promise<RelayerInfo | RelayerError | undefined> {
const hostname = relayer.hostnames[this.netId]; const hostname = relayer.hostnames[netId];
const { ensName, relayerAddress } = relayer; const { ensName, relayerAddress } = relayer;
if (!hostname) { if (!hostname) {
@@ -263,8 +257,8 @@ export class RelayerClient {
try { try {
const status = await this.askRelayerStatus({ const status = await this.askRelayerStatus({
netId,
hostname, hostname,
relayerAddress,
}); });
return { return {
@@ -292,13 +286,16 @@ export class RelayerClient {
} }
} }
async getValidRelayers(relayers: CachedRelayerInfo[]): Promise<{ async getValidRelayers(
netId: NetIdType,
relayers: CachedRelayerInfo[],
): Promise<{
validRelayers: RelayerInfo[]; validRelayers: RelayerInfo[];
invalidRelayers: RelayerError[]; invalidRelayers: RelayerError[];
}> { }> {
const invalidRelayers: RelayerError[] = []; const invalidRelayers: RelayerError[] = [];
const validRelayers = (await Promise.all(relayers.map((relayer) => this.filterRelayer(relayer)))).filter( const validRelayers = (await Promise.all(relayers.map((relayer) => this.filterRelayer(netId, relayer)))).filter(
(r) => { (r) => {
if (!r) { if (!r) {
return false; return false;
@@ -331,7 +328,7 @@ export class RelayerClient {
* Request new job * Request new job
*/ */
const withdrawResponse = (await fetchData(`${url}v1/tornadoWithdraw`, { const withdrawResponse = await fetchData<RelayerTornadoWithdraw>(`${url}v1/tornadoWithdraw`, {
...this.fetchDataOptions, ...this.fetchDataOptions,
method: 'POST', method: 'POST',
headers: { headers: {
@@ -342,7 +339,7 @@ export class RelayerClient {
proof, proof,
args, args,
}), }),
})) as RelayerTornadoWithdraw; });
const { id, error } = withdrawResponse; const { id, error } = withdrawResponse;
@@ -372,7 +369,7 @@ export class RelayerClient {
console.log(`Job submitted: ${jobUrl}\n`); console.log(`Job submitted: ${jobUrl}\n`);
while (!relayerStatus || !['FAILED', 'CONFIRMED'].includes(relayerStatus)) { while (!relayerStatus || !['FAILED', 'CONFIRMED'].includes(relayerStatus)) {
const jobResponse = await fetchData(jobUrl, { const jobResponse = await fetchData<RelayerTornadoJobs>(jobUrl, {
...this.fetchDataOptions, ...this.fetchDataOptions,
method: 'GET', method: 'GET',
headers: { headers: {
@@ -391,7 +388,7 @@ export class RelayerClient {
throw new Error(errMsg); throw new Error(errMsg);
} }
const { status, txHash, confirmations, failedReason } = jobResponse as unknown as RelayerTornadoJobs; const { status, txHash, confirmations, failedReason } = jobResponse;
if (relayerStatus !== status) { if (relayerStatus !== status) {
if (status === 'FAILED') { if (status === 'FAILED') {

View File

@@ -1,4 +1,4 @@
import { Config, NetId, NetIdType } from '../networkConfig'; import { Config } from '../networkConfig';
import { addressSchemaType, bnSchemaType } from '.'; import { addressSchemaType, bnSchemaType } from '.';
export interface statusInstanceType { export interface statusInstanceType {
@@ -6,13 +6,12 @@ export interface statusInstanceType {
properties: { properties: {
instanceAddress: { instanceAddress: {
type: string; type: string;
properties: { properties: Record<string, typeof addressSchemaType>;
[key in string]: typeof addressSchemaType;
};
required: string[]; required: string[];
}; };
tokenAddress?: typeof addressSchemaType; tokenAddress?: typeof addressSchemaType;
symbol?: { enum: string[] }; //symbol?: { enum: string[] };
symbol?: { type: string };
decimals: { enum: number[] }; decimals: { enum: number[] };
}; };
required: string[]; required: string[];
@@ -20,17 +19,13 @@ export interface statusInstanceType {
export interface statusInstancesType { export interface statusInstancesType {
type: string; type: string;
properties: { properties: Record<string, statusInstanceType>;
[key in string]: statusInstanceType;
};
required: string[]; required: string[];
} }
export interface statusEthPricesType { export interface statusEthPricesType {
type: string; type: string;
properties: { properties: Record<string, typeof bnSchemaType>;
[key in string]: typeof bnSchemaType;
};
required?: string[]; required?: string[];
} }
@@ -41,11 +36,12 @@ export interface statusSchema {
instances?: statusInstancesType; instances?: statusInstancesType;
gasPrices: { gasPrices: {
type: string; type: string;
properties: { properties: Record<
[key in string]: { string,
{
type: string; type: string;
}; }
}; >;
required: string[]; required: string[];
}; };
netId: { netId: {
@@ -132,15 +128,23 @@ const statusSchema: statusSchema = {
required: ['rewardAccount', 'instances', 'netId', 'tornadoServiceFee', 'version', 'health', 'currentQueue'], required: ['rewardAccount', 'instances', 'netId', 'tornadoServiceFee', 'version', 'health', 'currentQueue'],
}; };
export function getStatusSchema(netId: NetIdType, config: Config, tovarish: boolean) { export function getStatusSchema(config: Config, tovarish: boolean) {
const { tokens, optionalTokens, disabledTokens, nativeCurrency } = config; const { tokens, nativeCurrency } = config;
// deep copy schema // deep copy schema
const schema = JSON.parse(JSON.stringify(statusSchema)) as statusSchema; const schema = JSON.parse(JSON.stringify(statusSchema)) as statusSchema;
const instances = Object.keys(tokens).reduce( const instances = Object.keys(tokens).reduce(
(acc: statusInstancesType, token) => { (acc: statusInstancesType, token) => {
const { instanceAddress, tokenAddress, symbol, decimals, optionalInstances = [] } = tokens[token]; const {
isOptional,
isDisabled,
instanceAddress,
tokenAddress,
symbol,
decimals,
optionalInstances = [],
} = tokens[token];
const amounts = Object.keys(instanceAddress); const amounts = Object.keys(instanceAddress);
const instanceProperties: statusInstanceType = { const instanceProperties: statusInstanceType = {
@@ -148,18 +152,10 @@ export function getStatusSchema(netId: NetIdType, config: Config, tovarish: bool
properties: { properties: {
instanceAddress: { instanceAddress: {
type: 'object', type: 'object',
properties: amounts.reduce( properties: amounts.reduce((acc: Record<string, typeof addressSchemaType>, cur) => {
(
acc: {
[key in string]: typeof addressSchemaType;
},
cur,
) => {
acc[cur] = addressSchemaType; acc[cur] = addressSchemaType;
return acc; return acc;
}, }, {}),
{},
),
required: amounts.filter((amount) => !optionalInstances.includes(amount)), required: amounts.filter((amount) => !optionalInstances.includes(amount)),
}, },
decimals: { enum: [decimals] }, decimals: { enum: [decimals] },
@@ -173,12 +169,14 @@ export function getStatusSchema(netId: NetIdType, config: Config, tovarish: bool
if (tokenAddress) { if (tokenAddress) {
instanceProperties.properties.tokenAddress = addressSchemaType; instanceProperties.properties.tokenAddress = addressSchemaType;
} }
if (symbol) { if (symbol) {
instanceProperties.properties.symbol = { enum: [symbol] }; // instanceProperties.properties.symbol = { enum: [symbol] };
instanceProperties.properties.symbol = { type: 'string' };
} }
acc.properties[token] = instanceProperties; acc.properties[token] = instanceProperties;
if (!optionalTokens?.includes(token) && !disabledTokens?.includes(token)) { if (!isOptional && !isDisabled) {
acc.required.push(token); acc.required.push(token);
} }
return acc; return acc;
@@ -192,18 +190,12 @@ export function getStatusSchema(netId: NetIdType, config: Config, tovarish: bool
schema.properties.instances = instances; schema.properties.instances = instances;
const _tokens = Object.keys(tokens).filter( const _tokens = instances.required.filter((t) => t !== nativeCurrency);
(t) => t !== nativeCurrency && !config.optionalTokens?.includes(t) && !config.disabledTokens?.includes(t),
);
if (netId === NetId.MAINNET) {
_tokens.push('torn');
}
if (_tokens.length) { if (_tokens.length) {
const ethPrices: statusEthPricesType = { const ethPrices: statusEthPricesType = {
type: 'object', type: 'object',
properties: _tokens.reduce((acc: { [key in string]: typeof bnSchemaType }, token: string) => { properties: _tokens.reduce((acc: Record<string, typeof bnSchemaType>, token: string) => {
acc[token] = bnSchemaType; acc[token] = bnSchemaType;
return acc; return acc;
}, {}), }, {}),

View File

@@ -11,7 +11,7 @@ import {
import { fetchData } from './providers'; import { fetchData } from './providers';
import { CachedRelayerInfo, MinimalEvents } from './events'; import { CachedRelayerInfo, MinimalEvents } from './events';
import { ajv, getEventsSchemaValidator, getStatusSchema } from './schemas'; import { ajv, getEventsSchemaValidator, getStatusSchema } from './schemas';
import { enabledChains, getConfig, NetId, NetIdType } from './networkConfig'; import { NetId, NetIdType } from './networkConfig';
// Return no more than 5K events per query // Return no more than 5K events per query
export const MAX_TOVARISH_EVENTS = 5000; export const MAX_TOVARISH_EVENTS = 5000;
@@ -76,10 +76,11 @@ export class TovarishClient extends RelayerClient {
} }
async askRelayerStatus({ async askRelayerStatus({
netId,
hostname, hostname,
url, url,
relayerAddress,
}: { }: {
netId: NetIdType;
hostname?: string; hostname?: string;
// optional url if entered manually // optional url if entered manually
url?: string; url?: string;
@@ -87,9 +88,9 @@ export class TovarishClient extends RelayerClient {
relayerAddress?: string; relayerAddress?: string;
}): Promise<TovarishStatus> { }): Promise<TovarishStatus> {
const status = (await super.askRelayerStatus({ const status = (await super.askRelayerStatus({
netId,
hostname, hostname,
url, url,
relayerAddress,
})) as TovarishStatus; })) as TovarishStatus;
if (!status.version.includes('tovarish')) { if (!status.version.includes('tovarish')) {
@@ -121,14 +122,14 @@ export class TovarishClient extends RelayerClient {
url = ''; url = '';
} }
const statusArray = (await fetchData(`${url}status`, { const statusArray = await fetchData<TovarishStatus[]>(`${url}status`, {
...this.fetchDataOptions, ...this.fetchDataOptions,
headers: { headers: {
'Content-Type': 'application/json, application/x-www-form-urlencoded', 'Content-Type': 'application/json, application/x-www-form-urlencoded',
}, },
timeout: 30000, timeout: 30000,
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0, maxRetry: this.fetchDataOptions?.dispatcher ? 2 : 0,
})) as object; });
if (!Array.isArray(statusArray)) { if (!Array.isArray(statusArray)) {
return []; return [];
@@ -137,33 +138,25 @@ export class TovarishClient extends RelayerClient {
const tovarishStatus: TovarishStatus[] = []; const tovarishStatus: TovarishStatus[] = [];
for (const rawStatus of statusArray) { for (const rawStatus of statusArray) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any const netId = rawStatus?.netId as NetIdType;
const netId = (rawStatus as any).netId as NetIdType; const config = this.tornadoConfig.getConfig(netId);
const config = getConfig(netId);
const statusValidator = ajv.compile( const statusValidator = ajv.compile(getStatusSchema(config, this.tovarish));
getStatusSchema(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(rawStatus as any).netId,
config,
this.tovarish,
),
);
if (!statusValidator) { if (!statusValidator(rawStatus)) {
continue; continue;
} }
const status = { const status = {
...rawStatus, ...rawStatus,
url: `${url}${netId}/`, url: `${url}${netId}/`,
} as TovarishStatus; };
if (status.currentQueue > 5) { if (status.currentQueue > 5) {
throw new Error('Withdrawal queue is overloaded'); throw new Error('Withdrawal queue is overloaded');
} }
if (!enabledChains.includes(status.netId)) { if (!this.tornadoConfig.chains.includes(status.netId)) {
throw new Error('This relayer serves a different network'); throw new Error('This relayer serves a different network');
} }
@@ -181,17 +174,21 @@ export class TovarishClient extends RelayerClient {
return tovarishStatus; return tovarishStatus;
} }
async filterRelayer(relayer: CachedRelayerInfo): Promise<TovarishInfo | RelayerError | undefined> { async filterRelayer(
netId: NetIdType,
relayer: CachedRelayerInfo,
): Promise<TovarishInfo | RelayerError | undefined> {
const { ensName, relayerAddress, tovarishHost, tovarishNetworks } = relayer; const { ensName, relayerAddress, tovarishHost, tovarishNetworks } = relayer;
if (!tovarishHost || !tovarishNetworks?.includes(this.netId)) { if (!tovarishHost || !tovarishNetworks?.includes(netId)) {
return; return;
} }
const hostname = `${tovarishHost}/${this.netId}`; const hostname = `${tovarishHost}/${netId}`;
try { try {
const status = await this.askRelayerStatus({ const status = await this.askRelayerStatus({
netId,
hostname, hostname,
relayerAddress, relayerAddress,
}); });
@@ -228,13 +225,16 @@ export class TovarishClient extends RelayerClient {
} }
} }
async getValidRelayers(relayers: CachedRelayerInfo[]): Promise<{ async getValidRelayers(
netId: NetIdType,
relayers: CachedRelayerInfo[],
): Promise<{
validRelayers: TovarishInfo[]; validRelayers: TovarishInfo[];
invalidRelayers: RelayerError[]; invalidRelayers: RelayerError[];
}> { }> {
const invalidRelayers: RelayerError[] = []; const invalidRelayers: RelayerError[] = [];
const validRelayers = (await Promise.all(relayers.map((relayer) => this.filterRelayer(relayer)))).filter( const validRelayers = (await Promise.all(relayers.map((relayer) => this.filterRelayer(netId, relayer)))).filter(
(r) => { (r) => {
if (!r) { if (!r) {
return false; return false;
@@ -327,7 +327,6 @@ export class TovarishClient extends RelayerClient {
const events = []; const events = [];
let lastSyncBlock = fromBlock; let lastSyncBlock = fromBlock;
// eslint-disable-next-line no-constant-condition
while (true) { while (true) {
// eslint-disable-next-line prefer-const // eslint-disable-next-line prefer-const
let { events: fetchedEvents, lastSyncBlock: currentBlock } = (await fetchData(url, { let { events: fetchedEvents, lastSyncBlock: currentBlock } = (await fetchData(url, {

View File

@@ -112,7 +112,7 @@ export function leInt2Buff(bigint: bnInput | bigint) {
return Uint8Array.from(new BN(bigint as bnInput).toArray('le', 31)); return Uint8Array.from(new BN(bigint as bnInput).toArray('le', 31));
} }
// Inherited from tornado-core and tornado-cli // Inherited from tornado-scripts and tornado-cli
export function toFixedHex(numberish: BigNumberish, length = 32) { export function toFixedHex(numberish: BigNumberish, length = 32) {
return ( return (
'0x' + '0x' +
@@ -122,17 +122,17 @@ export function toFixedHex(numberish: BigNumberish, length = 32) {
); );
} }
export function toFixedLength(string: string, length: number = 32) { export function toFixedLength(string: string, length = 32) {
string = string.replace('0x', ''); string = string.replace('0x', '');
return '0x' + string.padStart(length * 2, '0'); return '0x' + string.padStart(length * 2, '0');
} }
// Random BigInt in a range of bytes // Random BigInt in a range of bytes
export function rBigInt(nbytes: number = 31) { export function rBigInt(nbytes = 31) {
return bytesToBN(crypto.getRandomValues(new Uint8Array(nbytes))); return bytesToBN(crypto.getRandomValues(new Uint8Array(nbytes)));
} }
export function rHex(nbytes: number = 32) { export function rHex(nbytes = 32) {
return bytesToHex(crypto.getRandomValues(new Uint8Array(nbytes))); return bytesToHex(crypto.getRandomValues(new Uint8Array(nbytes)));
} }
@@ -142,7 +142,7 @@ export function bigIntReplacer(key: any, value: any) {
return typeof value === 'bigint' ? value.toString() : value; return typeof value === 'bigint' ? value.toString() : value;
} }
export function substring(str: string, length: number = 10) { export function substring(str: string, length = 10) {
if (str.length < length * 2) { if (str.length < length * 2) {
return str; return str;
} }
@@ -150,11 +150,11 @@ export function substring(str: string, length: number = 10) {
return `${str.substring(0, length)}...${str.substring(str.length - length)}`; return `${str.substring(0, length)}...${str.substring(str.length - length)}`;
} }
export async function digest(bytes: Uint8Array, algo: string = 'SHA-384') { export async function digest(bytes: Uint8Array, algo = 'SHA-384') {
return new Uint8Array(await crypto.subtle.digest(algo, bytes)); return new Uint8Array(await crypto.subtle.digest(algo, bytes));
} }
export function numberFormatter(num: string | number | bigint, digits: number = 3): string { export function numberFormatter(num: string | number | bigint, digits = 3): string {
const lookup = [ const lookup = [
{ value: 1, symbol: '' }, { value: 1, symbol: '' },
{ value: 1e3, symbol: 'K' }, { value: 1e3, symbol: 'K' },

View File

@@ -1,5 +1,15 @@
import { zip, unzip, AsyncZippable, Unzipped, ZipAttributes } from 'fflate'; import {
import { fetchData } from './providers'; zip,
unzip,
AsyncZippable,
Unzipped,
ZipAttributes,
zlib,
unzlib,
AsyncZlibOptions,
AsyncUnzlibOptions,
} from 'fflate';
import { fetchData, fetchDataOptions } from './providers';
import { bytesToBase64, digest } from './utils'; import { bytesToBase64, digest } from './utils';
export function zipAsync(file: AsyncZippable, options?: ZipAttributes): Promise<Uint8Array> { export function zipAsync(file: AsyncZippable, options?: ZipAttributes): Promise<Uint8Array> {
@@ -26,20 +36,47 @@ export function unzipAsync(data: Uint8Array): Promise<Unzipped> {
}); });
} }
export function zlibAsync(data: Uint8Array, options?: AsyncZlibOptions): Promise<Uint8Array> {
return new Promise((res, rej) => {
zlib(data, { ...(options || {}) }, (err, data) => {
if (err) {
rej(err);
return;
}
res(data);
});
});
}
export function unzlibAsync(data: Uint8Array, options?: AsyncUnzlibOptions): Promise<Uint8Array> {
return new Promise((res, rej) => {
unzlib(data, { ...(options || {}) }, (err, data) => {
if (err) {
rej(err);
return;
}
res(data);
});
});
}
export async function downloadZip<T>({ export async function downloadZip<T>({
staticUrl = '', staticUrl = '',
zipName, zipName,
zipDigest, zipDigest,
parseJson = true, parseJson = true,
fetchOptions,
}: { }: {
staticUrl?: string; staticUrl?: string;
zipName: string; zipName: string;
zipDigest?: string; zipDigest?: string;
parseJson?: boolean; parseJson?: boolean;
fetchOptions?: fetchDataOptions;
}): Promise<T> { }): Promise<T> {
const url = `${staticUrl}/${zipName}.zip`; const url = `${staticUrl}/${zipName}.zip`;
const resp = (await fetchData(url, { const resp = (await fetchData(url, {
...(fetchOptions || {}),
method: 'GET', method: 'GET',
returnResponse: true, returnResponse: true,
})) as Response; })) as Response;

View File

@@ -4,7 +4,7 @@ import { ethers } from 'hardhat';
import { expect } from 'chai'; import { expect } from 'chai';
import { formatEther } from 'ethers'; import { formatEther } from 'ethers';
import { ETHTornado__factory, Verifier__factory } from '@tornado/contracts'; import { ETHTornado__factory, Verifier__factory } from 'tornado-contracts';
import { Deposit, deployHasher } from '../src'; import { Deposit, deployHasher } from '../src';
const { getSigners } = ethers; const { getSigners } = ethers;

View File

@@ -3,5 +3,7 @@
"compilerOptions": { "compilerOptions": {
"rootDir": "./src" "rootDir": "./src"
}, },
"include": ["./src/**/*"],
"exclude": ["./test/**/*"],
"files": [] "files": []
} }

View File

@@ -110,6 +110,9 @@
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */ "skipLibCheck": true /* Skip type checking all .d.ts files. */
}, },
"include": ["./src/**/*"], "include": [
"./src/**/*",
"./test/**/*"
],
"files": ["./hardhat.config.ts"] "files": ["./hardhat.config.ts"]
} }

View File

@@ -1,15 +1,24 @@
const { BannerPlugin } = require('webpack'); const { BannerPlugin, ProvidePlugin } = require('webpack');
const path = require('path'); const path = require('path');
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin'); const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
const esbuildLoader = { const commonRules = [
{
test: /\.ts?$/, test: /\.ts?$/,
loader: 'esbuild-loader', loader: 'esbuild-loader',
options: { options: {
loader: 'ts', loader: 'ts',
target: 'es2022', target: 'es2022',
} }
} },
// Disable strict dependency resolution for ESM modules, so that polyfill plugin can handle the rest
{
test: /\.m?js$/,
resolve: {
fullySpecified: false
}
}
]
const commonAlias = { const commonAlias = {
fs: false, fs: false,
@@ -26,7 +35,7 @@ module.exports = [
{ {
mode: 'production', mode: 'production',
module: { module: {
rules: [esbuildLoader] rules: [...commonRules]
}, },
entry: './src/index.ts', entry: './src/index.ts',
output: { output: {
@@ -37,11 +46,18 @@ module.exports = [
}, },
plugins: [ plugins: [
new NodePolyfillPlugin(), new NodePolyfillPlugin(),
new ProvidePlugin({
process: 'process/browser',
Buffer: ['buffer', 'Buffer']
}),
], ],
resolve: { resolve: {
extensions: ['.tsx', '.ts', '.js'], extensions: ['.tsx', '.ts', '.js'],
alias: { alias: {
...commonAlias, ...commonAlias,
},
fallback: {
'process/browser': require.resolve('process/browser'),
} }
}, },
optimization: { optimization: {
@@ -51,7 +67,7 @@ module.exports = [
{ {
mode: 'production', mode: 'production',
module: { module: {
rules: [esbuildLoader] rules: [...commonRules]
}, },
entry: './src/index.ts', entry: './src/index.ts',
output: { output: {
@@ -62,18 +78,25 @@ module.exports = [
}, },
plugins: [ plugins: [
new NodePolyfillPlugin(), new NodePolyfillPlugin(),
new ProvidePlugin({
process: 'process/browser',
Buffer: ['buffer', 'Buffer']
}),
], ],
resolve: { resolve: {
extensions: ['.tsx', '.ts', '.js'], extensions: ['.tsx', '.ts', '.js'],
alias: { alias: {
...commonAlias, ...commonAlias,
},
fallback: {
'process/browser': require.resolve('process/browser'),
} }
}, },
}, },
{ {
mode: 'production', mode: 'production',
module: { module: {
rules: [esbuildLoader] rules: [...commonRules]
}, },
entry: './src/merkleTreeWorker.ts', entry: './src/merkleTreeWorker.ts',
output: { output: {
@@ -83,6 +106,10 @@ module.exports = [
}, },
plugins: [ plugins: [
new NodePolyfillPlugin(), new NodePolyfillPlugin(),
new ProvidePlugin({
process: 'process/browser',
Buffer: ['buffer', 'Buffer']
}),
new BannerPlugin({ new BannerPlugin({
banner: 'globalThis.process = { browser: true, env: {}, };\n', banner: 'globalThis.process = { browser: true, env: {}, };\n',
raw: true, raw: true,
@@ -92,6 +119,9 @@ module.exports = [
extensions: ['.tsx', '.ts', '.js'], extensions: ['.tsx', '.ts', '.js'],
alias: { alias: {
...commonAlias, ...commonAlias,
},
fallback: {
'process/browser': require.resolve('process/browser'),
} }
}, },
optimization: { optimization: {
@@ -101,7 +131,7 @@ module.exports = [
{ {
mode: 'production', mode: 'production',
module: { module: {
rules: [esbuildLoader] rules: [...commonRules]
}, },
entry: './src/merkleTreeWorker.ts', entry: './src/merkleTreeWorker.ts',
output: { output: {
@@ -111,6 +141,10 @@ module.exports = [
}, },
plugins: [ plugins: [
new NodePolyfillPlugin(), new NodePolyfillPlugin(),
new ProvidePlugin({
process: 'process/browser',
Buffer: ['buffer', 'Buffer']
}),
new BannerPlugin({ new BannerPlugin({
banner: 'globalThis.process = { browser: true, env: {}, };', banner: 'globalThis.process = { browser: true, env: {}, };',
raw: true, raw: true,
@@ -120,13 +154,16 @@ module.exports = [
extensions: ['.tsx', '.ts', '.js'], extensions: ['.tsx', '.ts', '.js'],
alias: { alias: {
...commonAlias, ...commonAlias,
},
fallback: {
'process/browser': require.resolve('process/browser'),
} }
}, },
}, },
{ {
mode: 'production', mode: 'production',
module: { module: {
rules: [esbuildLoader] rules: [...commonRules]
}, },
entry: './src/contracts.ts', entry: './src/contracts.ts',
output: { output: {
@@ -151,7 +188,7 @@ module.exports = [
{ {
mode: 'production', mode: 'production',
module: { module: {
rules: [esbuildLoader] rules: [...commonRules]
}, },
entry: './src/contracts.ts', entry: './src/contracts.ts',
output: { output: {

3100
yarn.lock

File diff suppressed because it is too large Load Diff