Compare commits

..

No commits in common. "b5c7dace4570b351e1170767b4c2bbd9ca4191d4" and "44f50a51d312998f40a8fc11101bc35a82c0e8ae" have entirely different histories.

11 changed files with 31209 additions and 30064 deletions

59338
dist/cli.js vendored

File diff suppressed because one or more lines are too long

4
dist/program.d.ts vendored

@ -1,7 +1,7 @@
import 'dotenv/config';
import { Command } from 'commander';
import { JsonRpcProvider, Provider, TransactionLike, Wallet, VoidSigner } from 'ethers';
import { getProviderOptions, TornadoWallet, TornadoVoidSigner, RelayerInfo, RelayerError, RelayerClient, fetchDataOptions, NetIdType, Config } from '@tornado/core';
import { getProviderOptions, TornadoWallet, TornadoVoidSigner, Relayer, RelayerInfo, RelayerError, RelayerClient, fetchDataOptions, NetIdType, Config } from '@tornado/core';
export type commonProgramOptions = {
rpc?: string;
ethRpc?: string;
@ -40,7 +40,7 @@ export declare function getProgramRelayer({ options, fetchDataOptions, netId, }:
fetchDataOptions?: fetchDataOptions;
netId: NetIdType;
}): Promise<{
validRelayers?: RelayerInfo[];
validRelayers?: RelayerInfo[] | Relayer[];
invalidRelayers?: RelayerError[];
relayerClient?: RelayerClient;
}>;

@ -1,5 +1,6 @@
/// <reference types="node" />
import { AsyncZippable, Unzipped } from 'fflate';
import { BaseEvents, CachedEvents, MinimalEvents } from '@tornado/core';
import { BaseEvents, MinimalEvents } from '@tornado/core';
export declare function existsAsync(fileOrDir: string): Promise<boolean>;
/**
* Supports legacy gz format for legacy UI
@ -30,4 +31,4 @@ export declare function loadCachedEvents<T extends MinimalEvents>({ name, cacheD
name: string;
cacheDirectory: string;
deployedBlock: number;
}): Promise<CachedEvents<T>>;
}): Promise<BaseEvents<T>>;

@ -1,4 +1,4 @@
import { BatchBlockOnProgress, BatchEventOnProgress, BaseTornadoService, BaseEncryptedNotesService, BaseGovernanceService, BaseRegistryService, BaseTornadoServiceConstructor, BaseEncryptedNotesServiceConstructor, BaseGovernanceServiceConstructor, BaseRegistryServiceConstructor, BaseEchoServiceConstructor, BaseEchoService, CachedRelayers } from '@tornado/core';
import { BatchBlockOnProgress, BatchEventOnProgress, BaseTornadoService, BaseEncryptedNotesService, BaseGovernanceService, BaseRegistryService, BaseTornadoServiceConstructor, BaseEncryptedNotesServiceConstructor, BaseGovernanceServiceConstructor, BaseRegistryServiceConstructor, BaseEchoServiceConstructor, BaseEchoService } from '@tornado/core';
import type { BaseEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, RegistersEvents, AllGovernanceEvents, EchoEvents } from '@tornado/core';
export type NodeTornadoServiceConstructor = BaseTornadoServiceConstructor & {
cacheDirectory?: string;
@ -13,7 +13,7 @@ export declare class NodeTornadoService extends BaseTornadoService {
updateBlockProgress({ currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]): void;
updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
getEventsFromDB(): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>>;
getEventsFromCache(): Promise<import("@tornado/core").CachedEvents<DepositsEvents | WithdrawalsEvents>>;
getEventsFromCache(): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>>;
saveEvents({ events, lastBlock }: BaseEvents<DepositsEvents | WithdrawalsEvents>): Promise<void>;
}
export type NodeEchoServiceConstructor = BaseEchoServiceConstructor & {
@ -27,7 +27,7 @@ export declare class NodeEchoService extends BaseEchoService {
updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
getEventsFromDB(): Promise<BaseEvents<EchoEvents>>;
getEventsFromCache(): Promise<import("@tornado/core").CachedEvents<EchoEvents>>;
getEventsFromCache(): Promise<BaseEvents<EchoEvents>>;
saveEvents({ events, lastBlock }: BaseEvents<EchoEvents>): Promise<void>;
}
export type NodeEncryptedNotesServiceConstructor = BaseEncryptedNotesServiceConstructor & {
@ -41,7 +41,7 @@ export declare class NodeEncryptedNotesService extends BaseEncryptedNotesService
updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
getEventsFromDB(): Promise<BaseEvents<EncryptedNotesEvents>>;
getEventsFromCache(): Promise<import("@tornado/core").CachedEvents<EncryptedNotesEvents>>;
getEventsFromCache(): Promise<BaseEvents<EncryptedNotesEvents>>;
saveEvents({ events, lastBlock }: BaseEvents<EncryptedNotesEvents>): Promise<void>;
}
export type NodeGovernanceServiceConstructor = BaseGovernanceServiceConstructor & {
@ -56,7 +56,7 @@ export declare class NodeGovernanceService extends BaseGovernanceService {
updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
updateTransactionProgress({ currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]): void;
getEventsFromDB(): Promise<BaseEvents<AllGovernanceEvents>>;
getEventsFromCache(): Promise<import("@tornado/core").CachedEvents<AllGovernanceEvents>>;
getEventsFromCache(): Promise<BaseEvents<AllGovernanceEvents>>;
saveEvents({ events, lastBlock }: BaseEvents<AllGovernanceEvents>): Promise<void>;
}
export type NodeRegistryServiceConstructor = BaseRegistryServiceConstructor & {
@ -66,13 +66,10 @@ export type NodeRegistryServiceConstructor = BaseRegistryServiceConstructor & {
export declare class NodeRegistryService extends BaseRegistryService {
cacheDirectory?: string;
userDirectory?: string;
constructor({ netId, provider, graphApi, subgraphName, RelayerRegistry, Aggregator, relayerEnsSubdomains, deployedBlock, fetchDataOptions, cacheDirectory, userDirectory, }: NodeRegistryServiceConstructor);
constructor({ netId, provider, graphApi, subgraphName, RelayerRegistry, deployedBlock, fetchDataOptions, cacheDirectory, userDirectory, }: NodeRegistryServiceConstructor);
updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
getEventsFromDB(): Promise<BaseEvents<RegistersEvents>>;
getEventsFromCache(): Promise<import("@tornado/core").CachedEvents<RegistersEvents>>;
getEventsFromCache(): Promise<BaseEvents<RegistersEvents>>;
saveEvents({ events, lastBlock }: BaseEvents<RegistersEvents>): Promise<void>;
getRelayersFromDB(): Promise<CachedRelayers>;
getRelayersFromCache(): Promise<CachedRelayers>;
saveRelayers({ timestamp, relayers }: CachedRelayers): Promise<void>;
}

@ -1,6 +1,6 @@
{
"name": "@tornado/cli",
"version": "1.0.5-alpha",
"version": "1.0.3-alpha",
"description": "Modern Toolsets for Privacy Pools on Ethereum",
"main": "./dist/cli.js",
"types": "./dist/cli.d.ts",
@ -51,21 +51,38 @@
"optionalDependencies": {},
"devDependencies": {
"@colors/colors": "1.5.0",
"@tornado/core": "git+https://git.tornado.ws/tornadocontrib/tornado-core.git#700426acb7a7de16884cb314c3a0220a51682d18",
"@metamask/eth-sig-util": "^7.0.1",
"@tornado/contracts": "1.0.0",
"@tornado/core": "git+https://git.tornado.ws/tornadocontrib/tornado-core.git#84b6ed368e75ec2957999bd86677797412da6f5f",
"@tornado/fixed-merkle-tree": "0.7.3",
"@tornado/snarkjs": "0.1.20",
"@tornado/websnark": "0.0.4",
"@typechain/ethers-v6": "^0.5.1",
"@types/bn.js": "^5.1.5",
"@types/circomlibjs": "^0.1.6",
"@types/figlet": "^1.5.8",
"@typescript-eslint/eslint-plugin": "^8.6.0",
"@typescript-eslint/parser": "^8.6.0",
"@types/node": "^20.12.5",
"@types/node-fetch": "^2.6.11",
"@typescript-eslint/eslint-plugin": "^7.6.0",
"@typescript-eslint/parser": "^7.6.0",
"ajv": "^8.12.0",
"bloomfilter.js": "^1.0.2",
"bn.js": "^5.2.1",
"circomlibjs": "0.1.7",
"cli-table3": "^0.6.4",
"commander": "^12.0.0",
"cross-fetch": "^4.0.0",
"dotenv": "^16.4.5",
"esbuild-loader": "^4.2.2",
"eslint": "8.57.0",
"esbuild": "^0.20.2",
"esbuild-loader": "^4.1.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import": "^2.30.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-prettier": "^5.1.3",
"ethers": "^6.12.0",
"ffjavascript": "0.2.48",
"fflate": "^0.8.2",
"figlet": "^1.7.0",
"http-proxy-agent": "^7.0.2",
"https-proxy-agent": "^7.0.4",
@ -75,8 +92,8 @@
"ts-node": "^10.9.2",
"tsc": "^2.0.4",
"typechain": "^8.3.2",
"typescript": "^5.6.2",
"webpack": "^5.94.0",
"typescript": "^5.4.4",
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4"
}
}

@ -45,13 +45,14 @@ import {
tokenBalances,
Deposit,
DepositsEvents,
WithdrawalsEvents,
Relayer,
RelayerInfo,
RelayerError,
RelayerClient,
WithdrawalsEvents,
TornadoFeeOracle,
TokenPriceOracle,
calculateSnarkProof,
RelayerClient,
MerkleTreeService,
multicall,
Invoice,
@ -60,6 +61,7 @@ import {
NetId,
NetIdType,
getInstanceByAddress,
getSubdomains,
getConfig,
Config,
enabledChains,
@ -67,7 +69,6 @@ import {
NoteAccount,
getSupportedInstances,
initGroth16,
getRelayerEnsSubdomains,
} from '@tornado/core';
import * as packageJson from '../package.json';
import {
@ -229,17 +230,11 @@ export function getProgramGraphAPI(options: commonProgramOptions, config: Config
return '';
}
if (options.graph) {
return options.graph;
if (!options.graph) {
return Object.values(config.subgraphs)[0].url;
}
const predefinedUrl = Object.values(config.subgraphs)?.[0]?.url;
if (predefinedUrl) {
return predefinedUrl;
}
return '';
return options.graph;
}
export function getProgramProvider(
@ -284,7 +279,7 @@ export async function getProgramRelayer({
fetchDataOptions?: fetchDataOptions;
netId: NetIdType;
}): Promise<{
validRelayers?: RelayerInfo[];
validRelayers?: RelayerInfo[] | Relayer[];
invalidRelayers?: RelayerError[];
relayerClient?: RelayerClient;
}> {
@ -294,6 +289,8 @@ export async function getProgramRelayer({
const ethConfig = getConfig(RELAYER_NETWORK);
const subdomains = getSubdomains();
const {
aggregatorContract,
registryContract,
@ -313,16 +310,12 @@ export async function getProgramRelayer({
ethConfig,
);
const relayerEnsSubdomains = getRelayerEnsSubdomains();
const registryService = new NodeRegistryService({
netId: RELAYER_NETWORK,
provider,
graphApi,
subgraphName: registrySubgraph,
RelayerRegistry: RelayerRegistry__factory.connect(registryContract as string, provider),
Aggregator: Aggregator__factory.connect(aggregatorContract as string, provider),
relayerEnsSubdomains,
deployedBlock: REGISTRY_BLOCK,
fetchDataOptions,
cacheDirectory: EVENTS_DIR,
@ -332,56 +325,56 @@ export async function getProgramRelayer({
const relayerClient = new RelayerClient({
netId,
config: netConfig,
Aggregator: Aggregator__factory.connect(aggregatorContract as string, provider),
fetchDataOptions,
});
// If user provided relayer is a full working URL
if (relayer && relayer.startsWith('http')) {
const relayerStatus = await relayerClient.askRelayerStatus({
hostname: new URL(relayer).hostname,
});
if (relayer) {
if (!relayer.endsWith('.eth')) {
const relayerStatus = await relayerClient.askRelayerStatus({
hostname: new URL(relayer).hostname,
});
relayerClient.selectedRelayer = {
ensName: new URL(relayer).hostname,
relayerAddress: getAddress(relayerStatus.rewardAccount),
netId: relayerStatus.netId,
url: relayerStatus.url,
hostname: new URL(relayerStatus.url).hostname,
rewardAccount: getAddress(relayerStatus.rewardAccount),
instances: getSupportedInstances(relayerStatus.instances),
gasPrice: relayerStatus.gasPrices?.fast,
ethPrices: relayerStatus.ethPrices,
currentQueue: relayerStatus.currentQueue,
tornadoServiceFee: relayerStatus.tornadoServiceFee,
};
relayerClient.selectedRelayer = {
netId: relayerStatus.netId,
url: relayerStatus.url,
hostname: new URL(relayerStatus.url).hostname,
rewardAccount: getAddress(relayerStatus.rewardAccount),
instances: getSupportedInstances(relayerStatus.instances),
gasPrice: relayerStatus.gasPrices?.fast,
ethPrices: relayerStatus.ethPrices,
currentQueue: relayerStatus.currentQueue,
tornadoServiceFee: relayerStatus.tornadoServiceFee,
};
return {
validRelayers: [relayerClient.selectedRelayer],
invalidRelayers: [],
relayerClient,
};
return {
validRelayers: [relayerClient.selectedRelayer],
invalidRelayers: [],
relayerClient,
};
} else {
const { validRelayers } = await relayerClient.getValidRelayers([{ ensName: relayer }], subdomains, true);
const relayerStatus = validRelayers[0];
if (relayerStatus) {
relayerClient.selectedRelayer = relayerStatus;
}
return {
validRelayers,
invalidRelayers: [],
relayerClient,
};
}
}
console.log('\nGetting valid relayers from registry, would take some time\n');
const { validRelayers, invalidRelayers } = await relayerClient.getValidRelayers(
(await registryService.updateRelayers()).relayers,
await registryService.fetchRelayers(),
subdomains,
);
// If user has provided either a hostname or ensname of known registered relayer
const foundRelayer = relayer
? validRelayers.find((r) => r.hostname.includes(relayer) || r.ensName.includes(relayer))
: undefined;
if (foundRelayer) {
relayerClient.selectedRelayer = foundRelayer;
return {
validRelayers: [foundRelayer],
invalidRelayers: [],
relayerClient,
};
}
await registryService.saveEventsPromise;
const relayerStatus = relayerClient.pickWeightedRandomRelayer(validRelayers);
@ -909,6 +902,8 @@ export function tornadoProgram() {
const withdrawalEvents = (await withdrawalsService.updateEvents()).events as WithdrawalsEvents[];
await Promise.all([depositsService.saveEventsPromise, withdrawalsService.saveEventsPromise]);
const depositEvent = depositEvents.find(({ commitment }) => commitment === commitmentHex);
const withdrawalEvent = withdrawalEvents.find(({ nullifierHash }) => nullifierHash === nullifierHex);
@ -1280,6 +1275,8 @@ export function tornadoProgram() {
console.log('\n\n' + complianceTable.toString() + '\n');
await Promise.all([depositsService.saveEventsPromise, withdrawalsService.saveEventsPromise]);
process.exit(0);
});
@ -1306,7 +1303,6 @@ export function tornadoProgram() {
routerContract,
echoContract,
registryContract,
aggregatorContract,
governanceContract,
deployedBlock,
constants: { GOVERNANCE_BLOCK, REGISTRY_BLOCK, NOTE_ACCOUNT_BLOCK, ENCRYPTED_NOTES_BLOCK },
@ -1331,26 +1327,24 @@ export function tornadoProgram() {
});
await governanceService.updateEvents();
await governanceService.saveEventsPromise;
}
if (registryContract && aggregatorContract) {
const relayerEnsSubdomains = getRelayerEnsSubdomains();
if (registryContract) {
const registryService = new NodeRegistryService({
netId,
provider,
graphApi,
subgraphName: registrySubgraph,
RelayerRegistry: RelayerRegistry__factory.connect(registryContract, provider),
Aggregator: Aggregator__factory.connect(aggregatorContract, provider),
relayerEnsSubdomains,
deployedBlock: REGISTRY_BLOCK,
fetchDataOptions,
cacheDirectory: EVENTS_DIR,
userDirectory: SAVED_DIR,
});
await registryService.updateRelayers();
await registryService.updateEvents();
await registryService.saveEventsPromise;
}
const echoService = new NodeEchoService({
@ -1366,6 +1360,7 @@ export function tornadoProgram() {
});
await echoService.updateEvents();
await echoService.saveEventsPromise;
const encryptedNotesService = new NodeEncryptedNotesService({
netId,
@ -1380,6 +1375,7 @@ export function tornadoProgram() {
});
await encryptedNotesService.updateEvents();
await encryptedNotesService.saveEventsPromise;
const currencies = currencyOpts ? [currencyOpts.toLowerCase()] : Object.keys(tokens);
@ -1450,6 +1446,8 @@ export function tornadoProgram() {
if (nativeCurrency === currency) {
await treeCache.createTree(depositEvents, tree);
}
await Promise.all([depositsService.saveEventsPromise, withdrawalsService.saveEventsPromise]);
}
}
}
@ -1494,7 +1492,7 @@ export function tornadoProgram() {
netId,
url,
ensName,
stakeBalance ? `${Number(stakeBalance).toFixed(5)} TORN` : '',
stakeBalance ? `${Number(formatEther(stakeBalance)).toFixed(5)} TORN` : '',
relayerAddress,
rewardAccount,
currentQueue,
@ -1584,6 +1582,7 @@ export function tornadoProgram() {
console.log('Getting historic note accounts would take a while\n');
const echoEvents = (await echoService.updateEvents()).events;
await echoService.saveEventsPromise;
const userEvents = echoEvents.filter(({ address }) => address === signer.address);
@ -1694,6 +1693,7 @@ export function tornadoProgram() {
});
const encryptedNoteEvents = (await encryptedNotesService.updateEvents()).events;
await encryptedNotesService.saveEventsPromise;
const accountsTable = new Table();

@ -2,7 +2,7 @@ import path from 'path';
import { deflate, constants } from 'zlib';
import { stat, mkdir, readFile, writeFile } from 'fs/promises';
import { zip, unzip, AsyncZippable, Unzipped } from 'fflate';
import { BaseEvents, CachedEvents, MinimalEvents } from '@tornado/core';
import { BaseEvents, MinimalEvents } from '@tornado/core';
export async function existsAsync(fileOrDir: string): Promise<boolean> {
try {
@ -161,7 +161,7 @@ export async function loadCachedEvents<T extends MinimalEvents>({
name: string;
cacheDirectory: string;
deployedBlock: number;
}): Promise<CachedEvents<T>> {
}): Promise<BaseEvents<T>> {
try {
const module = await download({ cacheDirectory, name });
@ -173,14 +173,12 @@ export async function loadCachedEvents<T extends MinimalEvents>({
return {
events,
lastBlock,
fromCache: true,
};
}
return {
events: [],
lastBlock: deployedBlock,
fromCache: true,
};
} catch (err) {
console.log('Method loadCachedEvents has error');
@ -188,7 +186,6 @@ export async function loadCachedEvents<T extends MinimalEvents>({
return {
events: [],
lastBlock: deployedBlock,
fromCache: true,
};
}
}

@ -1,5 +1,3 @@
import path from 'path';
import { readFile } from 'fs/promises';
import Table from 'cli-table3';
import moment from 'moment';
import {
@ -16,7 +14,6 @@ import {
BaseEchoServiceConstructor,
BaseEchoService,
DEPOSIT,
CachedRelayers,
} from '@tornado/core';
import type {
BaseEvents,
@ -27,7 +24,7 @@ import type {
AllGovernanceEvents,
EchoEvents,
} from '@tornado/core';
import { saveUserFile, loadSavedEvents, loadCachedEvents, saveLegacyFile, existsAsync } from './data';
import { saveUserFile, loadSavedEvents, loadCachedEvents, saveLegacyFile } from './data';
export type NodeTornadoServiceConstructor = BaseTornadoServiceConstructor & {
cacheDirectory?: string;
@ -145,7 +142,6 @@ export class NodeTornadoService extends BaseTornadoService {
return {
events: [],
lastBlock: this.deployedBlock,
fromCache: true,
};
}
@ -318,7 +314,6 @@ export class NodeEchoService extends BaseEchoService {
return {
events: [],
lastBlock: this.deployedBlock,
fromCache: true,
};
}
@ -464,7 +459,6 @@ export class NodeEncryptedNotesService extends BaseEncryptedNotesService {
return {
events: [],
lastBlock: this.deployedBlock,
fromCache: true,
};
}
@ -628,7 +622,6 @@ export class NodeGovernanceService extends BaseGovernanceService {
return {
events: [],
lastBlock: this.deployedBlock,
fromCache: true,
};
}
@ -696,8 +689,6 @@ export class NodeRegistryService extends BaseRegistryService {
graphApi,
subgraphName,
RelayerRegistry,
Aggregator,
relayerEnsSubdomains,
deployedBlock,
fetchDataOptions,
cacheDirectory,
@ -709,8 +700,6 @@ export class NodeRegistryService extends BaseRegistryService {
graphApi,
subgraphName,
RelayerRegistry,
Aggregator,
relayerEnsSubdomains,
deployedBlock,
fetchDataOptions,
});
@ -778,7 +767,6 @@ export class NodeRegistryService extends BaseRegistryService {
return {
events: [],
lastBlock: this.deployedBlock,
fromCache: true,
};
}
@ -829,73 +817,4 @@ export class NodeRegistryService extends BaseRegistryService {
});
}
}
async getRelayersFromDB(): Promise<CachedRelayers> {
const filePath = path.join(this.userDirectory || '', 'relayers.json');
if (!this.userDirectory || !(await existsAsync(filePath))) {
return {
timestamp: 0,
relayers: [],
};
}
try {
const { timestamp, relayers } = JSON.parse(await readFile(filePath, { encoding: 'utf8' }));
return {
timestamp,
relayers,
};
} catch (err) {
console.log('Method getRelayersFromDB has error');
console.log(err);
return {
timestamp: 0,
relayers: [],
};
}
}
async getRelayersFromCache(): Promise<CachedRelayers> {
const filePath = path.join(this.cacheDirectory || '', 'relayers.json');
if (!this.cacheDirectory || !(await existsAsync(filePath))) {
return {
timestamp: 0,
relayers: [],
fromCache: true,
};
}
try {
const { timestamp, relayers } = JSON.parse(await readFile(filePath, { encoding: 'utf8' }));
return {
timestamp,
relayers,
fromCache: true,
};
} catch (err) {
console.log('Method getRelayersFromDB has error');
console.log(err);
return {
timestamp: 0,
relayers: [],
fromCache: true,
};
}
}
async saveRelayers({ timestamp, relayers }: CachedRelayers) {
if (this.userDirectory) {
await saveUserFile({
fileName: 'relayers.json',
userDirectory: this.userDirectory,
dataString: JSON.stringify({ timestamp, relayers }, null, 2) + '\n',
});
}
}
}

@ -1,357 +0,0 @@
{
"timestamp": 1726890359,
"relayers": [
{
"ensName": "okrelayer.eth",
"relayerAddress": "0x0e9D9a828247F5eed7f6D31D213A39805De52441",
"isRegistered": true,
"owner": "0x0e9D9a828247F5eed7f6D31D213A39805De52441",
"stakeBalance": "4666.679387946529032297",
"hostnames": {
"1": "okrelayer.xyz",
"56": "binance.okrelayer.xyz",
"137": "polygon.okrelayer.xyz",
"42161": "arb.okrelayer.xyz"
}
},
{
"ensName": "quick-relayer.eth",
"relayerAddress": "0x187541D7D312F742040f270d0221B4Fe577934B0",
"isRegistered": true,
"owner": "0x187541D7D312F742040f270d0221B4Fe577934B0",
"stakeBalance": "2931.033250737658918569",
"hostnames": {
"1": "quick-relayer.xyz"
}
},
{
"ensName": "safety-relayer.eth",
"relayerAddress": "0xF1F4F76c9969eFbFB5C9A90a6E44c0E3696D3EF8",
"isRegistered": true,
"owner": "0xF1F4F76c9969eFbFB5C9A90a6E44c0E3696D3EF8",
"stakeBalance": "500.879215977529089999",
"hostnames": {
"1": "a-relayer.top",
"56": "bsc.a-relayer.top",
"137": "polygon.a-relayer.top"
}
},
{
"ensName": "k-relayer.eth",
"relayerAddress": "0xC49415493eB3Ec64a0F13D8AA5056f1CfC4ce35c",
"isRegistered": true,
"owner": "0xC49415493eB3Ec64a0F13D8AA5056f1CfC4ce35c",
"stakeBalance": "2194.529689989084430299",
"hostnames": {
"1": "black-hardy.com",
"56": "bsc.black-hardy.com"
}
},
{
"ensName": "relayer007.eth",
"relayerAddress": "0xa0109274F53609f6Be97ec5f3052C659AB80f012",
"isRegistered": true,
"owner": "0xa0109274F53609f6Be97ec5f3052C659AB80f012",
"stakeBalance": "4989.637826137906607638",
"hostnames": {
"1": "torn.relayersdao.finance",
"56": "bsc.relayersdao.finance",
"137": "matic.relayersdao.finance"
}
},
{
"ensName": "reltor.eth",
"relayerAddress": "0x4750BCfcC340AA4B31be7e71fa072716d28c29C5",
"isRegistered": true,
"owner": "0x4750BCfcC340AA4B31be7e71fa072716d28c29C5",
"stakeBalance": "19999.983956326624881327",
"hostnames": {
"1": "eth.reltor.su",
"56": "binance.reltor.su",
"137": "polygon.reltor.su"
}
},
{
"ensName": "best-relay.eth",
"relayerAddress": "0xe5A4c70113b90566BC5f80a3866935d0d52F990E",
"isRegistered": true,
"owner": "0xe5A4c70113b90566BC5f80a3866935d0d52F990E",
"stakeBalance": "2002.0",
"hostnames": {
"1": "best-relay.gato-miaouw.xyz",
"56": "bsc.gato-miaouw.xyz"
}
},
{
"ensName": "crelayer.eth",
"relayerAddress": "0x180c58B7305152357142b33Eea94cBB152058B61",
"isRegistered": true,
"owner": "0x180c58B7305152357142b33Eea94cBB152058B61",
"stakeBalance": "1460.389956347917729137",
"hostnames": {
"1": "eth.crelayer.xyz",
"56": "bsc.crelayer.xyz"
}
},
{
"ensName": "torn-city.eth",
"relayerAddress": "0xd04e9f0945DEA8373D882C730e2c93a74B591796",
"isRegistered": true,
"owner": "0xd04e9f0945DEA8373D882C730e2c93a74B591796",
"stakeBalance": "6715.49550101901162633",
"hostnames": {
"1": "torn-city.com",
"56": "bsc.torn-city.com"
}
},
{
"ensName": "torrelayer.eth",
"relayerAddress": "0x2Ee39Ff05643bC7cc9ed31B71e142429044A425C",
"isRegistered": true,
"owner": "0x2Ee39Ff05643bC7cc9ed31B71e142429044A425C",
"stakeBalance": "3734.220945056618867324",
"hostnames": {
"1": "tornima.xyz",
"56": "binance.tornima.xyz"
}
},
{
"ensName": "tornxdo.eth",
"relayerAddress": "0xB399aa4c2F1678f72529Cd125F82cEA2c2a823eD",
"isRegistered": true,
"owner": "0xB399aa4c2F1678f72529Cd125F82cEA2c2a823eD",
"stakeBalance": "983.310689667160962345",
"hostnames": {
"1": "tornado.evmjunkie.xyz"
}
},
{
"ensName": "0xgm777.eth",
"relayerAddress": "0x94596B6A626392F5D972D6CC4D929a42c2f0008c",
"isRegistered": true,
"owner": "0x94596B6A626392F5D972D6CC4D929a42c2f0008c",
"stakeBalance": "1979.261700994868938309",
"hostnames": {
"1": "main.gm777.xyz",
"56": "bsc.gm777.xyz",
"42161": "arb.gm777.xyz"
}
},
{
"ensName": "relayer-secure.eth",
"relayerAddress": "0xCEdac436cEA98E93F471331eCC693fF41D730921",
"isRegistered": true,
"owner": "0xCEdac436cEA98E93F471331eCC693fF41D730921",
"stakeBalance": "548.198082306127582623",
"hostnames": {
"1": "relsecc-mainnet.moon-relayer.app"
}
},
{
"ensName": "default-relayer.eth",
"relayerAddress": "0x5555555731006f71f121144534Ca7C8799F66AA3",
"isRegistered": true,
"owner": "0x5555555731006f71f121144534Ca7C8799F66AA3",
"stakeBalance": "5011.216884015043970278",
"hostnames": {
"1": "eth.default-relayer.com",
"56": "bsc.default-relayer.com"
}
},
{
"ensName": "t-relayer.eth",
"relayerAddress": "0x000000Cd6521Ed1a65FAe0678eA15aF4EEAD74fe",
"isRegistered": true,
"owner": "0x000000Cd6521Ed1a65FAe0678eA15aF4EEAD74fe",
"stakeBalance": "6079.008889316501226288",
"hostnames": {
"1": "eth.t-relayer.com",
"56": "bsc.t-relayer.com"
}
},
{
"ensName": "secure-relay.eth",
"relayerAddress": "0x1036AF02bCDb2e3A4db2d3D40b29e5054EDc79BA",
"isRegistered": true,
"owner": "0x1036AF02bCDb2e3A4db2d3D40b29e5054EDc79BA",
"stakeBalance": "6751.661507930994067422",
"hostnames": {
"1": "torn-relayer.duckdns.org"
}
},
{
"ensName": "torntorn.eth",
"relayerAddress": "0x1247749d7E28D357B4279110af0802603AC526cE",
"isRegistered": true,
"owner": "0x1247749d7E28D357B4279110af0802603AC526cE",
"stakeBalance": "5535.435044583932530913",
"hostnames": {
"1": "eth.fsdhreu39jfk.com",
"56": "bsc.fsdhreu39jfk.com",
"100": "gnosis.tornad0.com",
"137": "polygon.tornad0.com"
}
},
{
"ensName": "bitah.eth",
"relayerAddress": "0x7E3893725d4e238B4c8c83375bBAd024a66Ffa42",
"isRegistered": true,
"owner": "0x7E3893725d4e238B4c8c83375bBAd024a66Ffa42",
"stakeBalance": "503.237718892072788154",
"hostnames": {
"1": "tornado.bitah.link",
"56": "bsc-tornado.bitah.link",
"137": "polygon-tornado.bitah.link"
}
},
{
"ensName": "shadow-out.eth",
"relayerAddress": "0x9Ee26a4bFd731E8e742B65bF955814EADdd7F151",
"isRegistered": true,
"owner": "0x9Ee26a4bFd731E8e742B65bF955814EADdd7F151",
"stakeBalance": "3571.639136672079169166",
"hostnames": {
"1": "livetobecomeavillain",
"56": "justarandomdude",
"100": "everythingisburning"
}
},
{
"ensName": "torn-eth.eth",
"relayerAddress": "0x42FecB4137aFF76E0E85702ff4F339DbFe6D859E",
"isRegistered": true,
"owner": "0x42FecB4137aFF76E0E85702ff4F339DbFe6D859E",
"stakeBalance": "978.62598484549460861",
"hostnames": {
"1": "mainnet-tornado.50swap.com"
}
},
{
"ensName": "0xproxy.eth",
"relayerAddress": "0x08657a1f4C1F06d657F31767831421EE7FaDf549",
"isRegistered": true,
"owner": "0x08657a1f4C1F06d657F31767831421EE7FaDf549",
"stakeBalance": "705.605817336537209483",
"hostnames": {
"1": "mainnet.0x0relayer.xyz",
"56": "bsc.0x0relayer.xyz",
"137": "polygon.0x0relayer.xyz"
}
},
{
"ensName": "wetez.eth",
"relayerAddress": "0xe6184DA55174Cc0263a17eA2fc24E48511766505",
"isRegistered": true,
"owner": "0xe6184DA55174Cc0263a17eA2fc24E48511766505",
"stakeBalance": "567.980734786905511868",
"hostnames": {
"1": "tornado-1.wetez.io"
}
},
{
"ensName": "0xtorn.eth",
"relayerAddress": "0x9Ffbd3f9eE795A4fDa880ED553A2A4BD6D45CE5B",
"isRegistered": true,
"owner": "0x9Ffbd3f9eE795A4fDa880ED553A2A4BD6D45CE5B",
"stakeBalance": "4627.036617270139345308",
"hostnames": {
"1": "mainnet.al1n.cc",
"56": "bsc-tornado.al1n.cc"
}
},
{
"ensName": "reslayer.eth",
"relayerAddress": "0x7Ba6781620c91676B070D319E7E894BFd4A9eC81",
"isRegistered": true,
"owner": "0x7Ba6781620c91676B070D319E7E894BFd4A9eC81",
"stakeBalance": "879.305690438201312145",
"hostnames": {
"1": "mainnet-tornado.reslayer.xyz",
"56": "bsc-tornado.reslayer.xyz",
"100": "gnosis-tornado.reslayer.xyz",
"137": "polygon-tornado.reslayer.xyz",
"42161": "arbitrum-tornado.reslayer.xyz",
"43114": "avalanche-tornado.reslayer.xyz"
}
},
{
"ensName": "em3tornado.eth",
"relayerAddress": "0x3a1d526D09b7E59Fd88De4726f68A8246dDC2742",
"isRegistered": true,
"owner": "0x3a1d526D09b7E59Fd88De4726f68A8246dDC2742",
"stakeBalance": "16864.242955629118561145",
"hostnames": {
"1": "em3torn.com",
"10": "optimism.em3torn.com",
"56": "bsc.em3torn.com",
"137": "polygon.em3torn.com",
"42161": "arbitrum.em3torn.com",
"43114": "avax.em3torn.com"
}
},
{
"ensName": "on-sale.eth",
"relayerAddress": "0x63606C4011e97a73BCd844Cde6a38D45a728BC0E",
"isRegistered": true,
"owner": "0x63606C4011e97a73BCd844Cde6a38D45a728BC0E",
"stakeBalance": "4476.543684932880020592",
"hostnames": {
"1": "mainnet-tornado.appleworld.club",
"56": "bsc-tornado.appleworld.club"
}
},
{
"ensName": "relayernews.eth",
"relayerAddress": "0x6289C8a70EE2Ed6914834CaEa431F9a82c7eAf70",
"isRegistered": true,
"owner": "0x6289C8a70EE2Ed6914834CaEa431F9a82c7eAf70",
"stakeBalance": "1661.181918638614466424",
"hostnames": {
"1": "mainnet-tornado.relayernews.xyz",
"56": "bsc-tornado.relayernews.xyz"
}
},
{
"ensName": "lowcost.eth",
"relayerAddress": "0x28907F21F43B419F34226d6f10aCbCf1832b1D4d",
"isRegistered": true,
"owner": "0x28907F21F43B419F34226d6f10aCbCf1832b1D4d",
"stakeBalance": "500.279638085962965981",
"hostnames": {
"1": "mainnet-tornado.low-fee.xyz",
"56": "bsc-tornado.low-fee.xyz",
"137": "polygon-tornado.low-fee.xyz",
"43114": "avalanche-tornado.low-fee.xyz"
}
},
{
"ensName": "cheap-relayer.eth",
"relayerAddress": "0x076D4E32C6A5D888fC4658281539c94E778C796d",
"isRegistered": true,
"owner": "0x076D4E32C6A5D888fC4658281539c94E778C796d",
"stakeBalance": "500.878420081833044818",
"hostnames": {
"1": "mainnet-tornado.cheap-relayer.xyz",
"56": "bsc-tornado.cheap-relayer.xyz",
"137": "polygon-tornado.cheap-relayer.xyz",
"43114": "avalanche-tornado.cheap-relayer.xyz"
}
},
{
"ensName": "therelayer.eth",
"relayerAddress": "0xA0F0287683E820FF4211e67C03cf46a87431f4E1",
"isRegistered": true,
"owner": "0xA0F0287683E820FF4211e67C03cf46a87431f4E1",
"stakeBalance": "1335.888771359625809238",
"hostnames": {
"1": "mainnet.therelayer.xyz",
"10": "optimism.therelayer.xyz",
"56": "bsc.therelayer.xyz",
"100": "xdai.therelayer.xyz",
"137": "polygon.therelayer.xyz",
"42161": "arbitrum.therelayer.xyz",
"43114": "avalanche.therelayer.xyz"
}
}
]
}

@ -1,3 +1,4 @@
const esbuild = require('esbuild');
const path = require('path');
const { BannerPlugin } = require('webpack');
@ -7,6 +8,7 @@ const esbuildLoader = {
options: {
loader: 'ts',
target: 'es2016',
implementation: esbuild
}
}

1293
yarn.lock

File diff suppressed because it is too large Load Diff