Compare commits

...

10 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
37 changed files with 258153 additions and 231739 deletions

View File

@@ -7,7 +7,7 @@ RUN apt update && apt install --yes --no-install-recommends wget git apt-transpo
ENV GIT_REPOSITORY=https://github.com/tornadocontrib/tornado-scripts.git ENV GIT_REPOSITORY=https://github.com/tornadocontrib/tornado-scripts.git
# From main branch, double check with git.tornado.ws and codeberg.org # From main branch, double check with git.tornado.ws and codeberg.org
ENV GIT_COMMIT_HASH=d143bc2923e4dcb1c84e4123fbc56cb406e6db6f ENV GIT_COMMIT_HASH=8d5658ee7aedbaa2413868c4c9e0fb453a92ae64
# clone the repository # clone the repository
RUN mkdir /app/ RUN mkdir /app/

44
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';
@@ -158,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);
@@ -181,7 +181,6 @@ export declare class BaseGovernanceService extends BaseEventsService<AllGovernan
balance: bigint; balance: bigint;
}>; }>;
} }
export declare function getTovarishNetworks(registryService: BaseRegistryService, relayers: CachedRelayerInfo[]): Promise<void>;
/** /**
* Essential params: * Essential params:
* ensName, relayerAddress, hostnames * ensName, relayerAddress, hostnames
@@ -189,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;

18
dist/hashes.json vendored
View File

@@ -1,11 +1,11 @@
{ {
"dist/index.js": "sha384-9VSo+DyOg7bk9fplN0eusAdRqdhB/o9VBM9Y4TinC0tYBljNm2IDfxC4G60luJDp", "dist/index.js": "sha384-ILYwPMkfXtfslWBdxqmKYYq4yDnJf3tKKgW5Am0P4NnpLW9z5m/wlLBuITa51727",
"dist/index.mjs": "sha384-Cm+w57MAhudCJ1Xk+H0dwspZlGJV3Yny1uFzoQBbNaCNaLwTH9CqDHdmu2mAYQxJ", "dist/index.mjs": "sha384-bgbAMKtG/iKiZKdITr1E+i14xCVp17/Yj8/O5bCE8BMnqlwTY/XvmLe8+EWmvB/s",
"dist/merkleTreeWorker.js": "sha384-HPaQH762jYxlfAdS4KPJou1AXG9Ww4N+PDEc6vHgFeIX1HI8S/StRmOoJR+gHScM", "dist/merkleTreeWorker.js": "sha384-CJID2MqR6z42NYw9ZXhHAZ05+7YrQg0YJDwJLB/qhOhIJYt3am2wVZdR/W7njnuZ",
"dist/merkleTreeWorker.umd.js": "sha384-+VOeGAa/XGNYsar06LgAquRWKO3CG7anvbpVvlWIa6J9pg9+DskqaDkAusiVz8HZ", "dist/merkleTreeWorker.umd.js": "sha384-6uVyasRLcNVbdsuJSbgzxfSQ/0yRURWhP6oULhW6jffTNJzpMWay6/ie9pQVUj78",
"dist/merkleTreeWorker.umd.min.js": "sha384-fOCKW9eYxMVLFTOQcuKJxJwNyRu6MRIzmPFHqzxlp0P/ZT24y+A3HcgCylohIfJ0", "dist/merkleTreeWorker.umd.min.js": "sha384-LUERJw4t5HapI287NVtz3VtnqjXXrC7yBdxMQHpkTX8ZGOjp5fyEqYb1KENzNY9R",
"dist/tornado.umd.js": "sha384-/dWCQ81GwzoRqHnv+pi9tsHj2mzMyvxBk5ttIbOLe/0MIcSw9aBoSr3vgRoSlWZ+", "dist/tornado.umd.js": "sha384-IXBljLi80UVwQj0arsdDbOLEQlHfXFAKbAencbqDgqyUaRs7mjsYJDFe+wPgB/ie",
"dist/tornado.umd.min.js": "sha384-CgPo6GlnCtdGLqeu7OIcOliLTRQy289Q3CxWv5xqXCQhrHxSUupP8nBv55xQiqkW", "dist/tornado.umd.min.js": "sha384-FwrFV3WOdr2uBRdFyPIKJU+gCybthzvw6+D9GDTRAYflL+Kh8C3hUyk7qsJJGGvq",
"dist/tornadoContracts.umd.js": "sha384-Gmawcz/XTH7WFUFnMJKPUCy2zrjDOhf/DtSv9xfHBulPyCEJwI70Hw+n7E1Y60EU", "dist/tornadoContracts.umd.js": "sha384-wOj+yVI78CBtmwvEn3l/ko3CEbtaqHXbx69pKraBOLOkz98HlJSSTcKs/spf0Ods",
"dist/tornadoContracts.umd.min.js": "sha384-Sclkp3xkhjmDekfQaQFkgUctmauYUF7ieeyyFhFBnwAzyp2eFBS5qzxvOIBhlJza" "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>;

2077
dist/index.js vendored

File diff suppressed because it is too large Load Diff

2058
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>;

16117
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

@@ -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,44 +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;
url: string;
}
export type RpcUrls = Record<string, RpcUrl>;
export interface SubgraphUrl {
name: string;
url: string;
}
export type SubgraphUrls = Record<string, SubgraphUrl>;
export interface TornadoInstance {
instanceAddress: Record<string, string>; instanceAddress: Record<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 type TokenInstances = Record<string, TornadoInstance>; export interface TornadoSingleInstance {
export interface Config { netId: NetId;
rpcCallRetryAttempt?: number; instanceAddress: string;
gasPrices: { instanceApproval?: boolean;
instant: number; isOptional?: boolean;
fast?: number; isDisabled?: boolean;
standard?: number; tokenAddress?: string;
low?: number; tokenGasLimit?: number;
maxPriorityFeePerGas?: number; currency: string;
}; amount: string;
nativeCurrency: string; decimals: number;
currencyName: string; gasLimit?: number;
explorerUrl: string; }
merkleTreeHeight: number; export type TokenInstances = Record<string, TornadoInstances>;
emptyElement: string; export type SubdomainMap = Record<NetIdType, string>;
export interface ConfigParams {
netId: NetIdType;
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;
@@ -62,53 +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 type networkConfig = Record<NetIdType, Config>; export interface TornadoConfigParams {
export type SubdomainMap = Record<NetIdType, string>; configs?: Record<NetIdType, ConfigParams>;
export declare const defaultConfig: networkConfig; governanceNetwork?: NetIdType;
export declare const enabledChains: NetIdType[]; relayerNetwork?: NetIdType;
/** }
* Custom config object to extend default config export declare class TornadoConfig {
* configs: Record<NetIdType, Config>;
* Inspired by getUrlFunc from ethers.js governanceNetwork: NetIdType;
* https://github.com/ethers-io/ethers.js/blob/v6/src.ts/utils/fetch.ts#L59 relayerNetwork: NetIdType;
*/ constructor(configParams?: TornadoConfigParams);
export declare let customConfig: networkConfig; get chains(): NetIdType[];
/** getConfig(netId: NetIdType): Config;
* Add or override existing network config object }
* export declare const defaultConfig: Record<NetIdType, ConfigParams>;
* 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): Record<string, DepositType>;

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';
@@ -109,24 +109,22 @@ export type RelayerInstanceList = Record<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,4 +1,4 @@
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;
@@ -10,7 +10,7 @@ export interface statusInstanceType {
}; };
tokenAddress?: typeof addressSchemaType; tokenAddress?: typeof addressSchemaType;
symbol?: { symbol?: {
enum: string[]; type: string;
}; };
decimals: { decimals: {
enum: number[]; enum: number[];
@@ -95,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;

326402
dist/tornado.umd.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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[];
}>; }>;

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>;

View File

@@ -1,6 +1,6 @@
{ {
"name": "tornado-scripts", "name": "tornado-scripts",
"version": "1.0.20", "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",
@@ -15,83 +15,87 @@
"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": "Tornado Contrib", "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.1.2", "@metamask/eth-sig-util": "^8.2.0",
"ajv": "^8.17.1", "ajv": "^8.17.1",
"bn.js": "^5.2.1", "bn.js": "^5.2.1",
"circomlibjs": "git+https://github.com/tornadocontrib/circomlibjs.git#2aef7aade8e2b8d103250e4b24c7f1526cf1dd8d", "circomlibjs": "git+https://github.com/tornadocontrib/circomlibjs.git#2aef7aade8e2b8d103250e4b24c7f1526cf1dd8d",
"cross-fetch": "^4.1.0", "ethers": "^6.13.5",
"ethers": "^6.13.4", "ffjavascript": "git+https://github.com/tornadocontrib/ffjavascript.git#fc766f09818d46967d1329c0fc8e361d8b349109",
"ffjavascript": "^0.3.1",
"fflate": "^0.8.2", "fflate": "^0.8.2",
"fixed-merkle-tree": "0.7.3", "fixed-merkle-tree": "0.7.3",
"idb": "^8.0.1",
"snarkjs": "git+https://github.com/tornadocontrib/snarkjs.git#2c964b3fe6019e057acab04cc17705d1f7fdaf9a", "snarkjs": "git+https://github.com/tornadocontrib/snarkjs.git#2c964b3fe6019e057acab04cc17705d1f7fdaf9a",
"tornado-contracts": "git+https://github.com/tornadocontrib/tornado-contracts.git#4c2fe0b80fa1a0571ffa538a046e234d4e38d140", "tornado-contracts": "git+https://github.com/tornadocontrib/tornado-contracts.git#a1c8fbd2919996a642a7de1abec86548ff64449b",
"websnark": "git+https://github.com/tornadocontrib/websnark.git#e5a79cca905d1ffb61a69739492be58d438c9f17" "websnark": "git+https://github.com/tornadocontrib/websnark.git#e5a79cca905d1ffb61a69739492be58d438c9f17"
}, },
"devDependencies": { "devDependencies": {
"@nomicfoundation/hardhat-chai-matchers": "^2.0.8", "@nomicfoundation/hardhat-chai-matchers": "^2.0.8",
"@nomicfoundation/hardhat-ethers": "^3.0.8", "@nomicfoundation/hardhat-ethers": "^3.0.8",
"@nomicfoundation/hardhat-ignition": "^0.15.9", "@nomicfoundation/hardhat-ignition": "^0.15.11",
"@nomicfoundation/hardhat-ignition-ethers": "^0.15.9", "@nomicfoundation/hardhat-ignition-ethers": "^0.15.11",
"@nomicfoundation/hardhat-network-helpers": "^1.0.12", "@nomicfoundation/hardhat-network-helpers": "^1.0.12",
"@nomicfoundation/hardhat-toolbox": "^5.0.0", "@nomicfoundation/hardhat-toolbox": "^5.0.0",
"@nomicfoundation/hardhat-verify": "^2.0.12", "@nomicfoundation/hardhat-verify": "^2.0.13",
"@rollup/plugin-commonjs": "^28.0.2", "@rollup/plugin-commonjs": "^28.0.3",
"@rollup/plugin-json": "^6.1.0", "@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^16.0.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": "^5.0.1", "@types/chai": "^5.2.1",
"@types/circomlibjs": "^0.1.6", "@types/circomlibjs": "^0.1.6",
"@types/mocha": "^10.0.10", "@types/mocha": "^10.0.10",
"@types/node": "^22.10.2", "@types/node": "^22.14.1",
"@types/node-fetch": "^2.6.12",
"chai": "^4.5.0", "chai": "^4.5.0",
"esbuild-loader": "^4.2.2", "esbuild-loader": "^4.3.0",
"eslint": "^9.17.0", "eslint": "^9.24.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^10.1.2",
"eslint-import-resolver-typescript": "^3.7.0", "eslint-import-resolver-typescript": "^4.3.2",
"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.2.0", "fetch-mock": "^12.5.2",
"hardhat": "^2.22.17", "hardhat": "^2.23.0",
"hardhat-gas-reporter": "^2.2.2", "hardhat-gas-reporter": "^2.2.3",
"mocha": "^11.0.1", "idb": "^8.0.2",
"mocha": "^11.1.0",
"node-polyfill-webpack-plugin": "^4.1.0", "node-polyfill-webpack-plugin": "^4.1.0",
"nyc": "^17.1.0", "nyc": "^17.1.0",
"prettier": "^3.4.2", "prettier": "^3.5.3",
"rollup": "^4.29.1", "rollup": "^4.40.0",
"rollup-plugin-esbuild": "^6.1.1", "rollup-plugin-esbuild": "^6.2.1",
"solidity-coverage": "^0.8.14", "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.7.2", "typescript": "^5.8.3",
"typescript-eslint": "^8.18.1", "typescript-eslint": "^8.30.1",
"webpack": "^5.97.1", "webpack": "^5.99.5",
"webpack-cli": "^6.0.1" "webpack-cli": "^6.0.1"
}, },
"resolutions": { "resolutions": {
@@ -99,6 +103,6 @@
"@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.3.1" "ffjavascript": "git+https://github.com/tornadocontrib/ffjavascript.git#fc766f09818d46967d1329c0fc8e361d8b349109"
} }
} }

View File

@@ -76,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,8 +17,8 @@ import {
Governance, Governance,
RelayerRegistry, RelayerRegistry,
Echoer, Echoer,
Aggregator,
Tornado__factory, Tornado__factory,
TovarishAggregator,
} from 'tornado-contracts'; } from 'tornado-contracts';
import type { MerkleTree } from 'fixed-merkle-tree'; import type { MerkleTree } from 'fixed-merkle-tree';
@@ -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';
@@ -816,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;
@@ -950,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),
]); ]);
@@ -1061,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),
]); ]);
@@ -1086,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
@@ -1115,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,
@@ -1171,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;
} }
@@ -1249,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
@@ -1320,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

@@ -62,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: {

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,
});
} }

File diff suppressed because it is too large Load Diff

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) { export async function fetchData<T>(url: string, options: fetchDataOptions = {}): Promise<T> {
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 = {}) {
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,7 +196,7 @@ 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 Record<string, any>; const headers = {} as Record<string, any>;
resp.headers.forEach((value: any, key: string) => { resp.headers.forEach((value: any, key: string) => {
@@ -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';
@@ -174,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}`;
@@ -212,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');
@@ -236,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) {
@@ -257,8 +257,8 @@ export class RelayerClient {
try { try {
const status = await this.askRelayerStatus({ const status = await this.askRelayerStatus({
netId,
hostname, hostname,
relayerAddress,
}); });
return { return {
@@ -286,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;
@@ -325,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: {
@@ -336,7 +339,7 @@ export class RelayerClient {
proof, proof,
args, args,
}), }),
})) as RelayerTornadoWithdraw; });
const { id, error } = withdrawResponse; const { id, error } = withdrawResponse;
@@ -366,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: {
@@ -385,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 {
@@ -10,7 +10,8 @@ export interface statusInstanceType {
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[];
@@ -127,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 = {
@@ -160,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;
@@ -179,13 +190,7 @@ 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 = {

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;

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' +

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

@@ -1,4 +1,4 @@
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');
@@ -46,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: {
@@ -71,11 +78,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'),
} }
}, },
}, },
@@ -92,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,
@@ -101,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: {
@@ -120,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,
@@ -129,6 +154,9 @@ module.exports = [
extensions: ['.tsx', '.ts', '.js'], extensions: ['.tsx', '.ts', '.js'],
alias: { alias: {
...commonAlias, ...commonAlias,
},
fallback: {
'process/browser': require.resolve('process/browser'),
} }
}, },
}, },

1909
yarn.lock

File diff suppressed because it is too large Load Diff