Compare commits

...

4 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
30 changed files with 239841 additions and 230099 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=0aa9f0038354412e01b171df7dcff96b1c55976c 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-iQ5shLTi2Nyi35ciUUQRXg2JSgjBguTRXafhYVZuuAyJug9BAXZIWYEwupPOUcCo", "dist/index.js": "sha384-ILYwPMkfXtfslWBdxqmKYYq4yDnJf3tKKgW5Am0P4NnpLW9z5m/wlLBuITa51727",
"dist/index.mjs": "sha384-Lx8Qc+R6ak1AaPmSKJ06+EYyFuVF8gI7E+IvBFItO+3Yoc+JmsunEmytkd7mhSQt", "dist/index.mjs": "sha384-bgbAMKtG/iKiZKdITr1E+i14xCVp17/Yj8/O5bCE8BMnqlwTY/XvmLe8+EWmvB/s",
"dist/merkleTreeWorker.js": "sha384-gib4Z6KDvYxUpNTSc4YA2dX5FxaQe2FiorGkBJJDfm86tXdT+57T2Gt+ti6YXTeX", "dist/merkleTreeWorker.js": "sha384-CJID2MqR6z42NYw9ZXhHAZ05+7YrQg0YJDwJLB/qhOhIJYt3am2wVZdR/W7njnuZ",
"dist/merkleTreeWorker.umd.js": "sha384-yHNYOc2TzXlkKS8/5dzjggHQmOJw2mRIB8DqagRTQxUP/p6uPXyp07LqXeOHNfv7", "dist/merkleTreeWorker.umd.js": "sha384-6uVyasRLcNVbdsuJSbgzxfSQ/0yRURWhP6oULhW6jffTNJzpMWay6/ie9pQVUj78",
"dist/merkleTreeWorker.umd.min.js": "sha384-Hpupvso1ruJIgbYwq+dySfLb75sgwxUexPYSCJu+/i7U3XqR6JiBhWOEnAdxR/An", "dist/merkleTreeWorker.umd.min.js": "sha384-LUERJw4t5HapI287NVtz3VtnqjXXrC7yBdxMQHpkTX8ZGOjp5fyEqYb1KENzNY9R",
"dist/tornado.umd.js": "sha384-ovBwiI34m1uBSV4UlKomzexgVturp0Uq7O207DMS96GwpOeOjdS1RMkh7rqmtMed", "dist/tornado.umd.js": "sha384-IXBljLi80UVwQj0arsdDbOLEQlHfXFAKbAencbqDgqyUaRs7mjsYJDFe+wPgB/ie",
"dist/tornado.umd.min.js": "sha384-z9UM5/+q0Z70nAb+8JebUO/78o9C/W1AZgOWOYsDAyL9sH8ANR9U9tfB467+QHCF", "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"
} }

4
dist/idb.d.ts vendored
View File

@@ -1,6 +1,6 @@
import type * as idb from 'idb'; import type * as idb from 'idb';
import type { OpenDBCallbacks, IDBPDatabase } from 'idb'; import type { OpenDBCallbacks, IDBPDatabase } from 'idb';
import { NetIdType } from './networkConfig'; import type { NetIdType, TornadoConfig } from './networkConfig';
declare global { declare global {
interface Window { interface Window {
idb: typeof idb; idb: typeof idb;
@@ -87,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>;

1843
dist/index.js vendored

File diff suppressed because it is too large Load Diff

1827
dist/index.mjs vendored

File diff suppressed because it is too large Load Diff

11
dist/ip.d.ts vendored
View File

@@ -7,3 +7,14 @@ export interface IPResult {
tor?: boolean; tor?: boolean;
} }
export declare function fetchIp(ipEcho: string, fetchOptions?: fetchDataOptions): Promise<IPResult>; export declare function fetchIp(ipEcho: string, fetchOptions?: fetchDataOptions): Promise<IPResult>;
export interface IPResultFuck {
YourFuckingIPAddress: string;
YourFuckingLocation: string;
YourFuckingHostname: string;
YourFuckingISP: string;
YourFuckingTorExit: boolean;
YourFuckingCity?: string;
YourFuckingCountry: string;
YourFuckingCountryCode: string;
}
export declare function fetchFuckingIp(ipFuck?: string, fetchOptions?: fetchDataOptions): Promise<IPResultFuck>;

View File

@@ -214,7 +214,7 @@ var hasRequiredFixedMerkleTree;
function requireFixedMerkleTree () { function requireFixedMerkleTree () {
if (hasRequiredFixedMerkleTree) return FixedMerkleTree; if (hasRequiredFixedMerkleTree) return FixedMerkleTree;
hasRequiredFixedMerkleTree = 1; hasRequiredFixedMerkleTree = 1;
var __importDefault = (FixedMerkleTree.__importDefault) || function (mod) { var __importDefault = (FixedMerkleTree && FixedMerkleTree.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(FixedMerkleTree, "__esModule", { value: true }); Object.defineProperty(FixedMerkleTree, "__esModule", { value: true });
@@ -337,7 +337,7 @@ var hasRequiredPartialMerkleTree;
function requirePartialMerkleTree () { function requirePartialMerkleTree () {
if (hasRequiredPartialMerkleTree) return PartialMerkleTree; if (hasRequiredPartialMerkleTree) return PartialMerkleTree;
hasRequiredPartialMerkleTree = 1; hasRequiredPartialMerkleTree = 1;
var __importDefault = (PartialMerkleTree.__importDefault) || function (mod) { var __importDefault = (PartialMerkleTree && PartialMerkleTree.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(PartialMerkleTree, "__esModule", { value: true }); Object.defineProperty(PartialMerkleTree, "__esModule", { value: true });
@@ -504,7 +504,7 @@ function requireLib () {
if (hasRequiredLib) return lib; if (hasRequiredLib) return lib;
hasRequiredLib = 1; hasRequiredLib = 1;
(function (exports) { (function (exports) {
var __importDefault = (lib.__importDefault) || function (mod) { var __importDefault = (lib && lib.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });

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,36 +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;
nativeCurrency: string; instanceAddress: string;
currencyName: string; instanceApproval?: boolean;
explorerUrl: string; isOptional?: boolean;
merkleTreeHeight: number; isDisabled?: boolean;
emptyElement: string; tokenAddress?: string;
tokenGasLimit?: number;
currency: string;
amount: string;
decimals: number;
gasLimit?: number;
}
export type TokenInstances = Record<string, TornadoInstances>;
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;
@@ -54,52 +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;
relayerEnsSubdomain: string;
tornadoSubgraph?: 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 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>;

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,23 +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, }: { askRelayerStatus({ netId, hostname, url, }: {
netId: NetIdType;
hostname?: string; hostname?: string;
url?: string; url?: 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;

324379
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, }: { 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[];
}>; }>;

View File

@@ -1,6 +1,6 @@
{ {
"name": "tornado-scripts", "name": "tornado-scripts",
"version": "1.0.21", "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",
@@ -17,7 +17,7 @@
"build": "yarn types && yarn build:node && yarn build:web && yarn build:hash", "build": "yarn types && yarn build:node && yarn build:web && yarn build:hash",
"docker:build": "docker build -t tornado-scripts .", "docker:build": "docker build -t tornado-scripts .",
"docker:hash": "docker container run --rm -it --entrypoint cat tornado-scripts /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",
@@ -42,60 +42,60 @@
], ],
"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",
"ethers": "^6.13.4", "ethers": "^6.13.5",
"ffjavascript": "git+https://github.com/tornadocontrib/ffjavascript.git#fc766f09818d46967d1329c0fc8e361d8b349109", "ffjavascript": "git+https://github.com/tornadocontrib/ffjavascript.git#fc766f09818d46967d1329c0fc8e361d8b349109",
"fflate": "^0.8.2", "fflate": "^0.8.2",
"fixed-merkle-tree": "0.7.3", "fixed-merkle-tree": "0.7.3",
"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#9be1e1c308ae891e939944b2220d9e2810e579f5", "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",
"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",
"idb": "^8.0.1", "idb": "^8.0.2",
"mocha": "^11.0.1", "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.2", "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": {

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?.dispatcher ? 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<Response>(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

@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any, import/no-duplicates */ /* eslint-disable @typescript-eslint/no-explicit-any, import/no-duplicates */
import type * as idb from 'idb'; import type * as idb from 'idb';
import type { OpenDBCallbacks, IDBPDatabase } from 'idb'; import type { OpenDBCallbacks, IDBPDatabase } from 'idb';
import { getConfig, NetIdType } from './networkConfig'; import type { NetIdType, TornadoConfig } from './networkConfig';
declare global { declare global {
interface Window { interface Window {
@@ -321,9 +321,9 @@ 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-scripts' }); const idb = new IndexedDB({ dbName: 'tornado-scripts' });
await idb.initDB(); await idb.initDB();
return idb; return idb;
@@ -370,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];
@@ -387,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

@@ -15,3 +15,23 @@ export function fetchIp(ipEcho: string, fetchOptions?: fetchDataOptions) {
timeout: 30000, timeout: 30000,
}); });
} }
// 🖕
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

@@ -263,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);
@@ -276,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;
@@ -295,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 || tx.nonce === 0 ? 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) {

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 { 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,29 +174,28 @@ 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,
}: { }: {
netId: NetIdType;
hostname?: string; hostname?: string;
// optional url if entered manually // optional url if entered manually
url?: string; url?: string;
@@ -218,7 +217,9 @@ export class RelayerClient {
maxRetry: this.fetchDataOptions?.dispatcher ? 2 : 0, maxRetry: this.fetchDataOptions?.dispatcher ? 2 : 0,
}); });
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');
@@ -233,7 +234,7 @@ 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');
} }
@@ -246,8 +247,8 @@ export class RelayerClient {
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) {
@@ -256,6 +257,7 @@ export class RelayerClient {
try { try {
const status = await this.askRelayerStatus({ const status = await this.askRelayerStatus({
netId,
hostname, hostname,
}); });
@@ -284,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;

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,9 +76,11 @@ export class TovarishClient extends RelayerClient {
} }
async askRelayerStatus({ async askRelayerStatus({
netId,
hostname, hostname,
url, url,
}: { }: {
netId: NetIdType;
hostname?: string; hostname?: string;
// optional url if entered manually // optional url if entered manually
url?: string; url?: string;
@@ -86,6 +88,7 @@ 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,
})) as TovarishStatus; })) as TovarishStatus;
@@ -136,9 +139,9 @@ export class TovarishClient extends RelayerClient {
for (const rawStatus of statusArray) { for (const rawStatus of statusArray) {
const netId = rawStatus?.netId as NetIdType; const netId = rawStatus?.netId as NetIdType;
const config = getConfig(netId); const config = this.tornadoConfig.getConfig(netId);
const statusValidator = ajv.compile(getStatusSchema(rawStatus?.netId, config, this.tovarish)); const statusValidator = ajv.compile(getStatusSchema(config, this.tovarish));
if (!statusValidator(rawStatus)) { if (!statusValidator(rawStatus)) {
continue; continue;
@@ -153,7 +156,7 @@ export class TovarishClient extends RelayerClient {
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');
} }
@@ -171,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,
}); });
@@ -218,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;

1863
yarn.lock

File diff suppressed because it is too large Load Diff