Compare commits

..

21 Commits

Author SHA1 Message Date
7befb1288d
Update events 2025-01-03 07:19:17 +00:00
b8ebf21cb4
Add APY command 2024-11-17 00:42:59 +00:00
b2f31b4e43
Use 4 tab size 2024-11-01 00:43:07 +00:00
42e6b1713b
Improved Note Encryption 2024-10-26 20:22:22 +00:00
48774c321e
Optional tree generation 2024-10-21 23:11:07 +00:00
53e60da285
Update tree generation 2024-10-21 11:51:15 +00:00
1217d411c2
Added Governance Commands 2024-10-20 11:33:13 +00:00
4512834388
Improve withdrawal confirmation tables 2024-10-11 22:47:02 +00:00
0a305433ba
Optimize mainnet fees 2024-10-10 23:23:55 +00:00
2eb489979c
Bump deps version 2024-10-10 05:47:05 +00:00
f51183f2c7
Improve relayer client 2024-10-08 14:00:50 +00:00
d19c062847
Sync relayers from RPC 2024-10-04 17:20:50 +00:00
620d46580b
Remove logging 2024-10-03 11:28:48 +00:00
75bb730713
Tornado-CLI 1.0.11-alpha
support tovarish relayer
2024-10-02 20:54:28 +00:00
29236fe7fd
Update built files 2024-09-26 12:49:02 +00:00
de6b929c51
Tornado CLI 1.0.10-alpha
use latest core deps
minor optimization
2024-09-26 12:46:23 +00:00
4c9fc48ad5
Tornado CLI 1.0.9-alpha
* improve event sync
* use latest core deps
2024-09-25 08:40:15 +00:00
37ce302ca5
Tornado CLI 1.0.8-alpha
audit provider network
2024-09-24 05:48:07 +00:00
a8fc72ccda
Tornado CLI 1.0.7-alpha
fixed encrypted events bug
2024-09-23 04:35:18 +00:00
083479bafc
Tornado CLI 1.0.6-alpha
minor improvements
2024-09-22 06:06:10 +00:00
b5c7dace45
Tornado CLI 1.0.5-alpha
revert back to .ws
2024-09-21 17:32:44 +00:00
169 changed files with 27931 additions and 12884 deletions

View File

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

1
.npmrc Normal file
View File

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

33019
dist/cli.js vendored

File diff suppressed because one or more lines are too long

30
dist/program.d.ts vendored
View File

@ -1,13 +1,11 @@
import 'dotenv/config'; import 'dotenv/config';
import { Command } from 'commander'; import { Command } from 'commander';
import { JsonRpcProvider, Provider, TransactionLike, Wallet, VoidSigner } from 'ethers'; 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, RelayerInfo, RelayerError, RelayerClient, fetchDataOptions, NetIdType, TovarishClient, TovarishInfo } from '@tornado/core';
export type commonProgramOptions = { export interface commonProgramOptions {
rpc?: string; rpc?: string;
ethRpc?: string; ethRpc?: string;
graph?: string; disableTovarish?: boolean;
ethGraph?: string;
disableGraph?: boolean;
accountKey?: string; accountKey?: string;
relayer?: string; relayer?: string;
walletWithdrawal?: boolean; walletWithdrawal?: boolean;
@ -19,7 +17,7 @@ export type commonProgramOptions = {
privateKey?: string; privateKey?: string;
nonInteractive?: boolean; nonInteractive?: boolean;
localRpc?: boolean; localRpc?: boolean;
}; }
export declare function promptConfirmation(nonInteractive?: boolean): Promise<void>; export declare function promptConfirmation(nonInteractive?: boolean): Promise<void>;
export declare function getIPAddress(fetchDataOptions: fetchDataOptions): Promise<{ export declare function getIPAddress(fetchDataOptions: fetchDataOptions): Promise<{
ip: any; ip: any;
@ -29,8 +27,7 @@ export declare function getProgramOptions(options: commonProgramOptions): Promis
options: commonProgramOptions; options: commonProgramOptions;
fetchDataOptions: fetchDataOptions; fetchDataOptions: fetchDataOptions;
}>; }>;
export declare function getProgramGraphAPI(options: commonProgramOptions, config: Config): string; export declare function getProgramProvider(rpcUrl: string | undefined, providerOptions: getProviderOptions): Promise<JsonRpcProvider>;
export declare function getProgramProvider(netId: NetIdType, rpcUrl: string | undefined, config: Config, providerOptions?: getProviderOptions): JsonRpcProvider;
export declare function getProgramSigner({ options, provider, }: { export declare function getProgramSigner({ options, provider, }: {
options: commonProgramOptions; options: commonProgramOptions;
provider: Provider; provider: Provider;
@ -40,13 +37,22 @@ export declare function getProgramRelayer({ options, fetchDataOptions, netId, }:
fetchDataOptions?: fetchDataOptions; fetchDataOptions?: fetchDataOptions;
netId: NetIdType; netId: NetIdType;
}): Promise<{ }): Promise<{
validRelayers?: RelayerInfo[]; validRelayers: RelayerInfo[];
invalidRelayers?: RelayerError[]; invalidRelayers: RelayerError[];
relayerClient?: RelayerClient; relayerClient: RelayerClient;
}>;
export declare function getTovarishRelayer({ options, fetchDataOptions, netId, }: {
options: commonProgramOptions;
fetchDataOptions?: fetchDataOptions;
netId: NetIdType;
}): Promise<{
validRelayers: TovarishInfo[];
invalidRelayers: RelayerError[];
relayerClient: TovarishClient;
}>; }>;
export declare function programSendTransaction({ signer, options, populatedTransaction, }: { export declare function programSendTransaction({ signer, options, populatedTransaction, }: {
signer: VoidSigner | Wallet; signer: VoidSigner | Wallet;
options: commonProgramOptions; options: commonProgramOptions;
populatedTransaction: TransactionLike; populatedTransaction: TransactionLike;
}): Promise<void>; }): Promise<import("ethers").TransactionResponse | undefined>;
export declare function tornadoProgram(): Command; export declare function tornadoProgram(): Command;

View File

@ -1,12 +1,9 @@
import { AsyncZippable, Unzipped } from 'fflate';
import { BaseEvents, CachedEvents, MinimalEvents } from '@tornado/core'; import { BaseEvents, CachedEvents, MinimalEvents } from '@tornado/core';
export declare function existsAsync(fileOrDir: string): Promise<boolean>; export declare function existsAsync(fileOrDir: string): Promise<boolean>;
/** /**
* Supports legacy gz format for legacy UI * Supports legacy gz format for legacy UI
*/ */
export declare function deflateAsync(data: Uint8Array): Promise<Buffer>; export declare function deflateAsync(data: Uint8Array): Promise<Buffer>;
export declare function zipAsync(file: AsyncZippable): Promise<Uint8Array>;
export declare function unzipAsync(data: Uint8Array): Promise<Unzipped>;
export declare function saveLegacyFile({ fileName, userDirectory, dataString, }: { export declare function saveLegacyFile({ fileName, userDirectory, dataString, }: {
fileName: string; fileName: string;
userDirectory: string; userDirectory: string;
@ -17,10 +14,9 @@ export declare function saveUserFile({ fileName, userDirectory, dataString, }: {
userDirectory: string; userDirectory: string;
dataString: string; dataString: string;
}): Promise<void>; }): Promise<void>;
export declare function loadSavedEvents<T extends MinimalEvents>({ name, userDirectory, deployedBlock, }: { export declare function loadSavedEvents<T extends MinimalEvents>({ name, userDirectory, }: {
name: string; name: string;
userDirectory: string; userDirectory: string;
deployedBlock: number;
}): Promise<BaseEvents<T>>; }): Promise<BaseEvents<T>>;
export declare function download({ name, cacheDirectory }: { export declare function download({ name, cacheDirectory }: {
name: string; name: string;

View File

@ -1,78 +1,82 @@
import { BatchBlockOnProgress, BatchEventOnProgress, BaseTornadoService, BaseEncryptedNotesService, BaseGovernanceService, BaseRegistryService, BaseTornadoServiceConstructor, BaseEncryptedNotesServiceConstructor, BaseGovernanceServiceConstructor, BaseRegistryServiceConstructor, BaseEchoServiceConstructor, BaseEchoService, CachedRelayers } from '@tornado/core'; import { BatchBlockOnProgress, BatchEventOnProgress, BaseTornadoService, BaseEncryptedNotesService, BaseGovernanceService, BaseRegistryService, BaseRevenueService, BaseTornadoServiceConstructor, BaseEncryptedNotesServiceConstructor, BaseGovernanceServiceConstructor, BaseRegistryServiceConstructor, BaseRevenueServiceConstructor, BaseEchoServiceConstructor, BaseEchoService, CachedRelayers, BaseEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, AllRelayerRegistryEvents, AllGovernanceEvents, EchoEvents, StakeBurnedEvents } from '@tornado/core';
import type { BaseEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, RegistersEvents, AllGovernanceEvents, EchoEvents } from '@tornado/core'; import { TreeCache } from './treeCache';
export type NodeTornadoServiceConstructor = BaseTornadoServiceConstructor & { export type NodeServiceConstructor = {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: string; userDirectory: string;
};
export type NodeTornadoServiceConstructor = BaseTornadoServiceConstructor & NodeServiceConstructor & {
nativeCurrency: string;
treeCache?: TreeCache;
}; };
export declare class NodeTornadoService extends BaseTornadoService { export declare class NodeTornadoService extends BaseTornadoService {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: string; userDirectory: string;
constructor({ netId, provider, graphApi, subgraphName, Tornado, type, amount, currency, deployedBlock, fetchDataOptions, cacheDirectory, userDirectory, }: NodeTornadoServiceConstructor); nativeCurrency: string;
treeCache?: TreeCache;
constructor(serviceConstructor: NodeTornadoServiceConstructor);
updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void; updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
updateTransactionProgress({ currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]): void; updateTransactionProgress({ currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]): void;
updateBlockProgress({ currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]): void; updateBlockProgress({ currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]): void;
updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
getEventsFromDB(): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>>; getEventsFromDB(): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>>;
getEventsFromCache(): Promise<import("@tornado/core").CachedEvents<DepositsEvents | WithdrawalsEvents>>; getEventsFromCache(): Promise<import("@tornado/core").CachedEvents<DepositsEvents | WithdrawalsEvents>>;
validateEvents<S>({ events, lastBlock, hasNewEvents, }: BaseEvents<DepositsEvents | WithdrawalsEvents> & {
hasNewEvents?: boolean;
}): Promise<S>;
saveEvents({ events, lastBlock }: BaseEvents<DepositsEvents | WithdrawalsEvents>): Promise<void>; saveEvents({ events, lastBlock }: BaseEvents<DepositsEvents | WithdrawalsEvents>): Promise<void>;
} }
export type NodeEchoServiceConstructor = BaseEchoServiceConstructor & { export type NodeEchoServiceConstructor = BaseEchoServiceConstructor & NodeServiceConstructor;
cacheDirectory?: string;
userDirectory?: string;
};
export declare class NodeEchoService extends BaseEchoService { export declare class NodeEchoService extends BaseEchoService {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: string; userDirectory: string;
constructor({ netId, provider, graphApi, subgraphName, Echoer, deployedBlock, fetchDataOptions, cacheDirectory, userDirectory, }: NodeEchoServiceConstructor); constructor(serviceConstructor: NodeEchoServiceConstructor);
updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void; updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
getEventsFromDB(): Promise<BaseEvents<EchoEvents>>; getEventsFromDB(): Promise<BaseEvents<EchoEvents>>;
getEventsFromCache(): Promise<import("@tornado/core").CachedEvents<EchoEvents>>; getEventsFromCache(): Promise<import("@tornado/core").CachedEvents<EchoEvents>>;
saveEvents({ events, lastBlock }: BaseEvents<EchoEvents>): Promise<void>; saveEvents({ events, lastBlock }: BaseEvents<EchoEvents>): Promise<void>;
} }
export type NodeEncryptedNotesServiceConstructor = BaseEncryptedNotesServiceConstructor & { export type NodeEncryptedNotesServiceConstructor = BaseEncryptedNotesServiceConstructor & NodeServiceConstructor;
cacheDirectory?: string;
userDirectory?: string;
};
export declare class NodeEncryptedNotesService extends BaseEncryptedNotesService { export declare class NodeEncryptedNotesService extends BaseEncryptedNotesService {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: string; userDirectory: string;
constructor({ netId, provider, graphApi, subgraphName, Router, deployedBlock, fetchDataOptions, cacheDirectory, userDirectory, }: NodeEncryptedNotesServiceConstructor); constructor(serviceConstructor: NodeEncryptedNotesServiceConstructor);
updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void; updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
getEventsFromDB(): Promise<BaseEvents<EncryptedNotesEvents>>; getEventsFromDB(): Promise<BaseEvents<EncryptedNotesEvents>>;
getEventsFromCache(): Promise<import("@tornado/core").CachedEvents<EncryptedNotesEvents>>; getEventsFromCache(): Promise<import("@tornado/core").CachedEvents<EncryptedNotesEvents>>;
saveEvents({ events, lastBlock }: BaseEvents<EncryptedNotesEvents>): Promise<void>; saveEvents({ events, lastBlock }: BaseEvents<EncryptedNotesEvents>): Promise<void>;
} }
export type NodeGovernanceServiceConstructor = BaseGovernanceServiceConstructor & { export type NodeGovernanceServiceConstructor = BaseGovernanceServiceConstructor & NodeServiceConstructor;
cacheDirectory?: string;
userDirectory?: string;
};
export declare class NodeGovernanceService extends BaseGovernanceService { export declare class NodeGovernanceService extends BaseGovernanceService {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: string; userDirectory: string;
constructor({ netId, provider, graphApi, subgraphName, Governance, deployedBlock, fetchDataOptions, cacheDirectory, userDirectory, }: NodeGovernanceServiceConstructor); constructor(serviceConstructor: NodeGovernanceServiceConstructor);
updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void; updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
updateTransactionProgress({ currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]): void; updateTransactionProgress({ currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]): void;
getEventsFromDB(): Promise<BaseEvents<AllGovernanceEvents>>; getEventsFromDB(): Promise<BaseEvents<AllGovernanceEvents>>;
getEventsFromCache(): Promise<import("@tornado/core").CachedEvents<AllGovernanceEvents>>; getEventsFromCache(): Promise<import("@tornado/core").CachedEvents<AllGovernanceEvents>>;
saveEvents({ events, lastBlock }: BaseEvents<AllGovernanceEvents>): Promise<void>; saveEvents({ events, lastBlock }: BaseEvents<AllGovernanceEvents>): Promise<void>;
} }
export type NodeRegistryServiceConstructor = BaseRegistryServiceConstructor & { export type NodeRegistryServiceConstructor = BaseRegistryServiceConstructor & NodeServiceConstructor;
cacheDirectory?: string;
userDirectory?: string;
};
export declare class NodeRegistryService extends BaseRegistryService { export declare class NodeRegistryService extends BaseRegistryService {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: string; userDirectory: string;
constructor({ netId, provider, graphApi, subgraphName, RelayerRegistry, Aggregator, relayerEnsSubdomains, deployedBlock, fetchDataOptions, cacheDirectory, userDirectory, }: NodeRegistryServiceConstructor); constructor(serviceConstructor: NodeRegistryServiceConstructor);
updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void; updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void; getEventsFromDB(): Promise<BaseEvents<AllRelayerRegistryEvents>>;
getEventsFromDB(): Promise<BaseEvents<RegistersEvents>>; getEventsFromCache(): Promise<import("@tornado/core").CachedEvents<AllRelayerRegistryEvents>>;
getEventsFromCache(): Promise<import("@tornado/core").CachedEvents<RegistersEvents>>; saveEvents({ events, lastBlock }: BaseEvents<AllRelayerRegistryEvents>): Promise<void>;
saveEvents({ events, lastBlock }: BaseEvents<RegistersEvents>): Promise<void>;
getRelayersFromDB(): Promise<CachedRelayers>; getRelayersFromDB(): Promise<CachedRelayers>;
getRelayersFromCache(): Promise<CachedRelayers>; getRelayersFromCache(): Promise<CachedRelayers>;
saveRelayers({ timestamp, relayers }: CachedRelayers): Promise<void>; saveRelayers({ lastBlock, timestamp, relayers }: CachedRelayers): Promise<void>;
}
export type NodeRevenueServiceConstructor = BaseRevenueServiceConstructor & NodeServiceConstructor;
export declare class NodeRevenueService extends BaseRevenueService {
cacheDirectory: string;
userDirectory: string;
constructor(serviceConstructor: NodeRevenueServiceConstructor);
updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
updateTransactionProgress({ currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]): void;
updateBlockProgress({ currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]): void;
getEventsFromDB(): Promise<BaseEvents<StakeBurnedEvents>>;
getEventsFromCache(): Promise<import("@tornado/core").CachedEvents<StakeBurnedEvents>>;
saveEvents({ events, lastBlock }: BaseEvents<StakeBurnedEvents>): Promise<void>;
} }

View File

@ -1,82 +1,85 @@
{ {
"name": "@tornado/cli", "name": "@tornado/cli",
"version": "1.0.4-alpha", "version": "1.0.11-alpha",
"description": "Modern Toolsets for Privacy Pools on Ethereum", "description": "Modern Toolsets for Privacy Pools on Ethereum",
"main": "./dist/cli.js", "main": "./dist/cli.js",
"types": "./dist/cli.d.ts", "types": "./dist/cli.d.ts",
"bin": { "bin": {
"tornado-cli": "./dist/cli.js" "tornado-cli": "./dist/cli.js"
}, },
"scripts": { "scripts": {
"typechain": "typechain --target ethers-v6 --out-dir src/typechain src/abi/*.json", "typechain": "typechain --target ethers-v6 --out-dir src/typechain src/abi/*.json",
"types": "tsc --declaration --emitDeclarationOnly", "types": "tsc --declaration --emitDeclarationOnly",
"lint": "eslint src/**/*.ts --ext .ts --ignore-pattern src/typechain", "lint": "eslint src/**/*.ts --ext .ts --ignore-pattern src/typechain",
"copy:worker": "ts-node scripts/copyFile.ts node_modules/@tornado/core/dist/merkleTreeWorker.js static/merkleTreeWorker.js", "copy:worker": "ts-node scripts/copyFile.ts node_modules/@tornado/core/dist/merkleTreeWorker.js static/merkleTreeWorker.js",
"build:node": "webpack", "build:node": "webpack",
"build": "yarn types && yarn build:node", "build": "yarn types && yarn build:node",
"start": "ts-node src/cli.ts", "start": "ts-node src/cli.ts",
"help": "ts-node src/cli.ts help", "help": "ts-node src/cli.ts help",
"create": "ts-node src/cli.ts create", "create": "ts-node src/cli.ts create",
"deposit": "ts-node src/cli.ts deposit", "deposit": "ts-node src/cli.ts deposit",
"depositInvoice": "ts-node src/cli.ts depositInvoice", "depositInvoice": "ts-node src/cli.ts depositInvoice",
"withdraw": "ts-node src/cli.ts withdraw", "withdraw": "ts-node src/cli.ts withdraw",
"compliance": "ts-node src/cli.ts compliance", "compliance": "ts-node src/cli.ts compliance",
"updateEvents": "ts-node src/cli.ts updateEvents", "updateEvents": "ts-node src/cli.ts updateEvents",
"relayers": "ts-node src/cli.ts relayers", "relayers": "ts-node src/cli.ts relayers",
"createAccount": "ts-node src/cli.ts createAccount", "createAccount": "ts-node src/cli.ts createAccount",
"decryptNotes": "ts-node src/cli.ts decryptNotes", "decrypt": "ts-node src/cli.ts decrypt",
"send": "ts-node src/cli.ts send", "send": "ts-node src/cli.ts send",
"balance": "ts-node src/cli.ts balance", "balance": "ts-node src/cli.ts balance",
"sign": "ts-node src/cli.ts sign", "sign": "ts-node src/cli.ts sign",
"broadcast": "ts-node src/cli.ts broadcast" "broadcast": "ts-node src/cli.ts broadcast",
}, "proposals": "ts-node src/cli.ts proposals",
"author": "", "delegates": "ts-node src/cli.ts delegates",
"license": "MIT", "apy": "ts-node src/cli.ts apy"
"files": [ },
"dist", "author": "",
"scripts", "license": "MIT",
"src", "files": [
"static", "dist",
".env.example", "scripts",
".eslintrc.js", "src",
".gitattributes", "static",
".gitignore", ".env.example",
".npmrc", ".eslintrc.js",
"logo.png", ".gitattributes",
"logo2.png", ".gitignore",
"tsconfig.json", ".npmrc",
"yarn.lock" "logo.png",
], "logo2.png",
"dependencies": {}, "tsconfig.json",
"optionalDependencies": {}, "yarn.lock"
"devDependencies": { ],
"@colors/colors": "1.5.0", "dependencies": {},
"@tornado/core": "git+https://codeberg.org/tornadocash/tornado-core.git#ef56beb29b3dc8808167acefe2bd23c2680643b2", "optionalDependencies": {},
"@typechain/ethers-v6": "^0.5.1", "devDependencies": {
"@types/figlet": "^1.5.8", "@colors/colors": "^1.6.0",
"@typescript-eslint/eslint-plugin": "^8.6.0", "@tornado/core": "git+https://git.tornado.ws/tornadocontrib/tornado-core.git#092989ebaa2fcd84eff7d4aed66433e77c790c60",
"@typescript-eslint/parser": "^8.6.0", "@typechain/ethers-v6": "^0.5.1",
"bloomfilter.js": "^1.0.2", "@types/figlet": "^1.7.0",
"cli-table3": "^0.6.4", "@typescript-eslint/eslint-plugin": "^8.11.0",
"commander": "^12.0.0", "@typescript-eslint/parser": "^8.11.0",
"dotenv": "^16.4.5", "bloomfilter.js": "^1.0.2",
"esbuild-loader": "^4.2.2", "cli-table3": "^0.6.4",
"eslint": "8.57.0", "commander": "^12.0.0",
"eslint-config-prettier": "^9.1.0", "dotenv": "^16.4.5",
"eslint-import-resolver-typescript": "^3.6.3", "esbuild-loader": "^4.2.2",
"eslint-plugin-import": "^2.30.0", "eslint": "8.57.0",
"eslint-plugin-prettier": "^5.2.1", "eslint-config-prettier": "^9.1.0",
"figlet": "^1.7.0", "eslint-import-resolver-typescript": "^3.6.3",
"http-proxy-agent": "^7.0.2", "eslint-plugin-import": "^2.31.0",
"https-proxy-agent": "^7.0.4", "eslint-plugin-prettier": "^5.2.1",
"moment": "^2.30.1", "figlet": "^1.8.0",
"prettier": "^3.2.5", "http-proxy-agent": "^7.0.2",
"socks-proxy-agent": "^8.0.3", "https-proxy-agent": "^7.0.4",
"ts-node": "^10.9.2", "moment": "^2.30.1",
"tsc": "^2.0.4", "prettier": "^3.2.5",
"typechain": "^8.3.2", "socks-proxy-agent": "^8.0.3",
"typescript": "^5.6.2", "ts-node": "^10.9.2",
"webpack": "^5.94.0", "tsc": "^2.0.4",
"webpack-cli": "^5.1.4" "typechain": "^8.3.2",
} "typescript": "^5.6.3",
"webpack": "^5.95.0",
"webpack-cli": "^5.1.4"
}
} }

View File

@ -2,14 +2,14 @@ import { argv } from 'process';
import { copyFile } from 'fs'; import { copyFile } from 'fs';
function copyFiles() { function copyFiles() {
const [, , inFile, outFile] = argv; const [, , inFile, outFile] = argv;
copyFile(inFile, outFile, function(err) { copyFile(inFile, outFile, function(err) {
if (err) { if (err) {
throw err; throw err;
} }
console.log(`Copied ${inFile} to ${outFile}`) console.log(`Copied ${inFile} to ${outFile}`)
}) })
} }
copyFiles() copyFiles()

File diff suppressed because it is too large Load Diff

View File

@ -1,194 +1,167 @@
import path from 'path'; import path from 'path';
import { deflate, constants } from 'zlib'; import { deflate, constants } from 'zlib';
import { stat, mkdir, readFile, writeFile } from 'fs/promises'; import { stat, mkdir, readFile, writeFile } from 'fs/promises';
import { zip, unzip, AsyncZippable, Unzipped } from 'fflate'; import { BaseEvents, CachedEvents, MinimalEvents, zipAsync, unzipAsync } from '@tornado/core';
import { BaseEvents, CachedEvents, MinimalEvents } from '@tornado/core';
export async function existsAsync(fileOrDir: string): Promise<boolean> { export async function existsAsync(fileOrDir: string): Promise<boolean> {
try { try {
await stat(fileOrDir); await stat(fileOrDir);
return true; return true;
} catch { } catch {
return false; return false;
} }
} }
/** /**
* Supports legacy gz format for legacy UI * Supports legacy gz format for legacy UI
*/ */
export function deflateAsync(data: Uint8Array): Promise<Buffer> { export function deflateAsync(data: Uint8Array): Promise<Buffer> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
deflate( deflate(
data, data,
{ {
level: constants.Z_BEST_COMPRESSION, level: constants.Z_BEST_COMPRESSION,
strategy: constants.Z_FILTERED, strategy: constants.Z_FILTERED,
}, },
(err, buffer) => { (err, buffer) => {
if (!err) { if (!err) {
resolve(buffer); resolve(buffer);
} else { } else {
reject(err); reject(err);
} }
}, },
); );
});
}
export function zipAsync(file: AsyncZippable): Promise<Uint8Array> {
return new Promise((res, rej) => {
zip(file, { mtime: new Date('1/1/1980') }, (err, data) => {
if (err) {
rej(err);
return;
}
res(data);
}); });
});
}
export function unzipAsync(data: Uint8Array): Promise<Unzipped> {
return new Promise((res, rej) => {
unzip(data, {}, (err, data) => {
if (err) {
rej(err);
return;
}
res(data);
});
});
} }
export async function saveLegacyFile({ export async function saveLegacyFile({
fileName, fileName,
userDirectory, userDirectory,
dataString, dataString,
}: { }: {
fileName: string; fileName: string;
userDirectory: string; userDirectory: string;
dataString: string; dataString: string;
}) { }) {
fileName = fileName.toLowerCase(); fileName = fileName.toLowerCase();
const filePath = path.join(userDirectory, fileName); const filePath = path.join(userDirectory, fileName);
const payload = await deflateAsync(new TextEncoder().encode(dataString)); const payload = await deflateAsync(new TextEncoder().encode(dataString));
if (!(await existsAsync(userDirectory))) { if (!(await existsAsync(userDirectory))) {
await mkdir(userDirectory, { recursive: true }); await mkdir(userDirectory, { recursive: true });
} }
await writeFile(filePath + '.gz', payload); await writeFile(filePath + '.gz', payload);
} }
export async function saveUserFile({ export async function saveUserFile({
fileName, fileName,
userDirectory, userDirectory,
dataString, dataString,
}: { }: {
fileName: string; fileName: string;
userDirectory: string; userDirectory: string;
dataString: string; dataString: string;
}) { }) {
fileName = fileName.toLowerCase(); fileName = fileName.toLowerCase();
const filePath = path.join(userDirectory, fileName); const filePath = path.join(userDirectory, fileName);
const payload = await zipAsync({ const payload = await zipAsync({
[fileName]: new TextEncoder().encode(dataString), [fileName]: new TextEncoder().encode(dataString),
}); });
if (!(await existsAsync(userDirectory))) { if (!(await existsAsync(userDirectory))) {
await mkdir(userDirectory, { recursive: true }); await mkdir(userDirectory, { recursive: true });
} }
await writeFile(filePath + '.zip', payload); await writeFile(filePath + '.zip', payload);
await writeFile(filePath, dataString); await writeFile(filePath, dataString);
} }
export async function loadSavedEvents<T extends MinimalEvents>({ export async function loadSavedEvents<T extends MinimalEvents>({
name, name,
userDirectory, userDirectory,
deployedBlock,
}: { }: {
name: string; name: string;
userDirectory: string; userDirectory: string;
deployedBlock: number;
}): Promise<BaseEvents<T>> { }): Promise<BaseEvents<T>> {
const filePath = path.join(userDirectory, `${name}.json`.toLowerCase()); const filePath = path.join(userDirectory, `${name}.json`.toLowerCase());
if (!(await existsAsync(filePath))) { if (!(await existsAsync(filePath))) {
return { return {
events: [] as T[], events: [] as T[],
lastBlock: null, lastBlock: 0,
}; };
} }
try { try {
const events = JSON.parse(await readFile(filePath, { encoding: 'utf8' })) as T[]; const events = JSON.parse(await readFile(filePath, { encoding: 'utf8' })) as T[];
return { return {
events, events,
lastBlock: events && events.length ? events[events.length - 1].blockNumber : deployedBlock, lastBlock: events[events.length - 1]?.blockNumber || 0,
}; };
} catch (err) { } catch (err) {
console.log('Method loadSavedEvents has error'); console.log('Method loadSavedEvents has error');
console.log(err); console.log(err);
return { return {
events: [], events: [],
lastBlock: deployedBlock, lastBlock: 0,
}; };
} }
} }
export async function download({ name, cacheDirectory }: { name: string; cacheDirectory: string }) { export async function download({ name, cacheDirectory }: { name: string; cacheDirectory: string }) {
const fileName = `${name}.json`.toLowerCase(); const fileName = `${name}.json`.toLowerCase();
const zipName = `${fileName}.zip`; const zipName = `${fileName}.zip`;
const zipPath = path.join(cacheDirectory, zipName); const zipPath = path.join(cacheDirectory, zipName);
const data = await readFile(zipPath); const data = await readFile(zipPath);
const { [fileName]: content } = await unzipAsync(data); const { [fileName]: content } = await unzipAsync(data);
return new TextDecoder().decode(content); return new TextDecoder().decode(content);
} }
export async function loadCachedEvents<T extends MinimalEvents>({ export async function loadCachedEvents<T extends MinimalEvents>({
name, name,
cacheDirectory, cacheDirectory,
deployedBlock, deployedBlock,
}: { }: {
name: string; name: string;
cacheDirectory: string; cacheDirectory: string;
deployedBlock: number; deployedBlock: number;
}): Promise<CachedEvents<T>> { }): Promise<CachedEvents<T>> {
try { try {
const module = await download({ cacheDirectory, name }); const module = await download({ cacheDirectory, name });
if (module) { if (module) {
const events = JSON.parse(module); const events = JSON.parse(module);
const lastBlock = events && events.length ? events[events.length - 1].blockNumber : deployedBlock; const lastBlock = events && events.length ? events[events.length - 1].blockNumber : deployedBlock;
return { return {
events, events,
lastBlock, lastBlock,
fromCache: true, fromCache: true,
}; };
}
return {
events: [],
lastBlock: deployedBlock,
fromCache: true,
};
} catch (err) {
console.log('Method loadCachedEvents has error');
console.log(err);
return {
events: [],
lastBlock: deployedBlock,
fromCache: true,
};
} }
return {
events: [],
lastBlock: deployedBlock,
fromCache: true,
};
} catch (err) {
console.log('Method loadCachedEvents has error');
console.log(err);
return {
events: [],
lastBlock: deployedBlock,
fromCache: true,
};
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -3,75 +3,75 @@ import { computeAddress, getAddress, Mnemonic } from 'ethers';
import { validateUrl } from '@tornado/core'; import { validateUrl } from '@tornado/core';
export function parseNumber(value?: string | number): number { export function parseNumber(value?: string | number): number {
if (!value || isNaN(Number(value))) { if (!value || isNaN(Number(value))) {
throw new InvalidArgumentError('Invalid Number'); throw new InvalidArgumentError('Invalid Number');
} }
return Number(value); return Number(value);
} }
export function parseUrl(value?: string): string { export function parseUrl(value?: string): string {
if (!value || !validateUrl(value, ['http:', 'https:'])) { if (!value || !validateUrl(value, ['http:', 'https:'])) {
throw new InvalidArgumentError('Invalid URL'); throw new InvalidArgumentError('Invalid URL');
} }
return value; return value;
} }
export function parseRelayer(value?: string): string { export function parseRelayer(value?: string): string {
if (!value || !(value.endsWith('.eth') || validateUrl(value, ['http:', 'https:']))) { if (!value || !(value.endsWith('.eth') || validateUrl(value, ['http:', 'https:']))) {
throw new InvalidArgumentError('Invalid Relayer ETH address or URL'); throw new InvalidArgumentError('Invalid Relayer ETH address or URL');
} }
return value; return value;
} }
export function parseAddress(value?: string): string { export function parseAddress(value?: string): string {
if (!value) { if (!value) {
throw new InvalidArgumentError('Invalid Address'); throw new InvalidArgumentError('Invalid Address');
} }
try { try {
return getAddress(value); return getAddress(value);
} catch { } catch {
throw new InvalidArgumentError('Invalid Address'); throw new InvalidArgumentError('Invalid Address');
} }
} }
export function parseMnemonic(value?: string): string { export function parseMnemonic(value?: string): string {
if (!value) { if (!value) {
throw new InvalidArgumentError('Invalid Mnemonic'); throw new InvalidArgumentError('Invalid Mnemonic');
} }
try { try {
Mnemonic.fromPhrase(value); Mnemonic.fromPhrase(value);
} catch { } catch {
throw new InvalidArgumentError('Invalid Mnemonic'); throw new InvalidArgumentError('Invalid Mnemonic');
} }
return value; return value;
} }
export function parseKey(value?: string): string { export function parseKey(value?: string): string {
if (!value) { if (!value) {
throw new InvalidArgumentError('Invalid Private Key'); throw new InvalidArgumentError('Invalid Private Key');
} }
if (value.length === 64) { if (value.length === 64) {
value = '0x' + value; value = '0x' + value;
} }
try { try {
computeAddress(value); computeAddress(value);
} catch { } catch {
throw new InvalidArgumentError('Invalid Private Key'); throw new InvalidArgumentError('Invalid Private Key');
} }
return value; return value;
} }
/** /**
* Recovery key shouldn't have a 0x prefix (Also this is how the UI generates) * Recovery key shouldn't have a 0x prefix (Also this is how the UI generates)
*/ */
export function parseRecoveryKey(value?: string): string { export function parseRecoveryKey(value?: string): string {
if (!value) { if (!value) {
throw new InvalidArgumentError('Invalid Recovery Key'); throw new InvalidArgumentError('Invalid Recovery Key');
} }
try { try {
computeAddress('0x' + value); computeAddress('0x' + value);
} catch { } catch {
throw new InvalidArgumentError('Invalid Recovery Key'); throw new InvalidArgumentError('Invalid Recovery Key');
} }
return value; return value;
} }

View File

@ -10,104 +10,104 @@ import type { NetIdType } from '@tornado/core';
import { saveUserFile } from './data'; import { saveUserFile } from './data';
export interface TreeCacheConstructor { export interface TreeCacheConstructor {
netId: NetIdType; netId: NetIdType;
amount: string; amount: string;
currency: string; currency: string;
userDirectory: string; userDirectory: string;
PARTS_COUNT?: number; PARTS_COUNT?: number;
LEAVES?: number; LEAVES?: number;
zeroElement?: string; zeroElement?: string;
} }
export interface treeMetadata { export interface treeMetadata {
blockNumber: number; blockNumber: number;
logIndex: number; logIndex: number;
transactionHash: string; transactionHash: string;
timestamp: number; timestamp: number;
from: string; from: string;
leafIndex: number; leafIndex: number;
} }
export class TreeCache { export class TreeCache {
netId: NetIdType; netId: NetIdType;
amount: string; amount: string;
currency: string; currency: string;
userDirectory: string; userDirectory: string;
PARTS_COUNT: number; PARTS_COUNT: number;
constructor({ netId, amount, currency, userDirectory, PARTS_COUNT = 4 }: TreeCacheConstructor) { constructor({ netId, amount, currency, userDirectory, PARTS_COUNT = 4 }: TreeCacheConstructor) {
this.netId = netId; this.netId = netId;
this.amount = amount; this.amount = amount;
this.currency = currency; this.currency = currency;
this.userDirectory = userDirectory; this.userDirectory = userDirectory;
this.PARTS_COUNT = PARTS_COUNT; this.PARTS_COUNT = PARTS_COUNT;
} }
getInstanceName(): string { getInstanceName(): string {
return `deposits_${this.netId}_${this.currency}_${this.amount}`; return `deposits_${this.netId}_${this.currency}_${this.amount}`;
} }
async createTree(events: DepositsEvents[], tree: MerkleTree) { async createTree(events: DepositsEvents[], tree: MerkleTree) {
const bloom = new BloomFilter(events.length); const bloom = new BloomFilter(events.length);
console.log(`Creating cached tree for ${this.getInstanceName()}\n`); console.log(`Creating cached tree for ${this.getInstanceName()}\n`);
// events indexed by commitment // events indexed by commitment
const eventsData = events.reduce( const eventsData = events.reduce(
(acc, { leafIndex, commitment, ...rest }, i) => { (acc, { leafIndex, commitment, ...rest }, i) => {
if (leafIndex !== i) { if (leafIndex !== i) {
throw new Error(`leafIndex (${leafIndex}) !== i (${i})`); throw new Error(`leafIndex (${leafIndex}) !== i (${i})`);
} }
acc[commitment] = { ...rest, leafIndex }; acc[commitment] = { ...rest, leafIndex };
return acc; return acc;
},
{} as { [key in string]: treeMetadata },
);
const slices = tree.getTreeSlices(this.PARTS_COUNT);
await Promise.all(
slices.map(async (slice, index) => {
const metadata = slice.elements.reduce((acc, curr) => {
if (index < this.PARTS_COUNT - 1) {
bloom.add(curr);
}
acc.push(eventsData[curr]);
return acc;
}, [] as treeMetadata[]);
const dataString =
JSON.stringify(
{
...slice,
metadata,
}, },
null, {} as { [key in string]: treeMetadata },
2, );
) + '\n';
const fileName = `${this.getInstanceName()}_slice${index + 1}.json`; const slices = tree.getTreeSlices(this.PARTS_COUNT);
await Promise.all(
slices.map(async (slice, index) => {
const metadata = slice.elements.reduce((acc, curr) => {
if (index < this.PARTS_COUNT - 1) {
bloom.add(curr);
}
acc.push(eventsData[curr]);
return acc;
}, [] as treeMetadata[]);
const dataString =
JSON.stringify(
{
...slice,
metadata,
},
null,
2,
) + '\n';
const fileName = `${this.getInstanceName()}_slice${index + 1}.json`;
await saveUserFile({
fileName,
userDirectory: this.userDirectory,
dataString,
});
}),
);
const dataString = bloom.serialize() + '\n';
const fileName = `${this.getInstanceName()}_bloom.json`;
await saveUserFile({ await saveUserFile({
fileName, fileName,
userDirectory: this.userDirectory, userDirectory: this.userDirectory,
dataString, dataString,
}); });
}), }
);
const dataString = bloom.serialize() + '\n';
const fileName = `${this.getInstanceName()}_bloom.json`;
await saveUserFile({
fileName,
userDirectory: this.userDirectory,
dataString,
});
}
} }

View File

@ -1,25 +1,25 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
declare module 'bloomfilter.js' { declare module 'bloomfilter.js' {
export default class BloomFilter { export default class BloomFilter {
m: number; m: number;
k: number; k: number;
size: number; size: number;
bitview: any; bitview: any;
constructor(n: number, false_postive_tolerance?: number); constructor(n: number, false_postive_tolerance?: number);
calculateHash(x: number, m: number, i: number): number; calculateHash(x: number, m: number, i: number): number;
test(data: any): boolean; test(data: any): boolean;
add(data: any): void; add(data: any): void;
bytelength(): number; bytelength(): number;
view(): Uint8Array; view(): Uint8Array;
serialize(): string; serialize(): string;
deserialize(serialized: string): BloomFilter; deserialize(serialized: string): BloomFilter;
} }
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,277 +1,85 @@
{ {
"timestamp": 1726890359, "lastBlock": 20874000,
"timestamp": 1727826179,
"relayers": [ "relayers": [
{ {
"ensName": "okrelayer.eth", "ensName": "tornadowithdraw.eth",
"relayerAddress": "0x0e9D9a828247F5eed7f6D31D213A39805De52441", "relayerAddress": "0x40c3d1656a26C9266f4A10fed0D87EFf79F54E64",
"hostnames": {},
"tovarishHost": "tornadowithdraw.com",
"tovarishNetworks": [
1,
56,
137,
10,
42161,
100,
43114,
11155111
]
},
{
"ensName": "therelayer.eth",
"relayerAddress": "0xA0F0287683E820FF4211e67C03cf46a87431f4E1",
"isRegistered": true, "isRegistered": true,
"owner": "0x0e9D9a828247F5eed7f6D31D213A39805De52441", "owner": "0xA0F0287683E820FF4211e67C03cf46a87431f4E1",
"stakeBalance": "4666.679387946529032297", "stakeBalance": "1335.888771359625809238",
"hostnames": { "hostnames": {
"1": "okrelayer.xyz", "1": "mainnet.therelayer.xyz",
"56": "binance.okrelayer.xyz", "10": "optimism.therelayer.xyz",
"137": "polygon.okrelayer.xyz", "56": "bsc.therelayer.xyz",
"42161": "arb.okrelayer.xyz" "100": "xdai.therelayer.xyz",
"137": "polygon.therelayer.xyz",
"42161": "arbitrum.therelayer.xyz",
"43114": "avalanche.therelayer.xyz"
} }
}, },
{ {
"ensName": "quick-relayer.eth", "ensName": "cheap-relayer.eth",
"relayerAddress": "0x187541D7D312F742040f270d0221B4Fe577934B0", "relayerAddress": "0x076D4E32C6A5D888fC4658281539c94E778C796d",
"isRegistered": true, "isRegistered": true,
"owner": "0x187541D7D312F742040f270d0221B4Fe577934B0", "owner": "0x076D4E32C6A5D888fC4658281539c94E778C796d",
"stakeBalance": "2931.033250737658918569", "stakeBalance": "500.878420081833044818",
"hostnames": { "hostnames": {
"1": "quick-relayer.xyz" "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": "safety-relayer.eth", "ensName": "lowcost.eth",
"relayerAddress": "0xF1F4F76c9969eFbFB5C9A90a6E44c0E3696D3EF8", "relayerAddress": "0x28907F21F43B419F34226d6f10aCbCf1832b1D4d",
"isRegistered": true, "isRegistered": true,
"owner": "0xF1F4F76c9969eFbFB5C9A90a6E44c0E3696D3EF8", "owner": "0x28907F21F43B419F34226d6f10aCbCf1832b1D4d",
"stakeBalance": "500.879215977529089999", "stakeBalance": "500.279638085962965981",
"hostnames": { "hostnames": {
"1": "a-relayer.top", "1": "mainnet-tornado.low-fee.xyz",
"56": "bsc.a-relayer.top", "56": "bsc-tornado.low-fee.xyz",
"137": "polygon.a-relayer.top" "137": "polygon-tornado.low-fee.xyz",
"43114": "avalanche-tornado.low-fee.xyz"
} }
}, },
{ {
"ensName": "k-relayer.eth", "ensName": "relayernews.eth",
"relayerAddress": "0xC49415493eB3Ec64a0F13D8AA5056f1CfC4ce35c", "relayerAddress": "0x6289C8a70EE2Ed6914834CaEa431F9a82c7eAf70",
"isRegistered": true, "isRegistered": true,
"owner": "0xC49415493eB3Ec64a0F13D8AA5056f1CfC4ce35c", "owner": "0x6289C8a70EE2Ed6914834CaEa431F9a82c7eAf70",
"stakeBalance": "2194.529689989084430299", "stakeBalance": "1661.181918638614466424",
"hostnames": { "hostnames": {
"1": "black-hardy.com", "1": "mainnet-tornado.relayernews.xyz",
"56": "bsc.black-hardy.com" "56": "bsc-tornado.relayernews.xyz"
} }
}, },
{ {
"ensName": "relayer007.eth", "ensName": "on-sale.eth",
"relayerAddress": "0xa0109274F53609f6Be97ec5f3052C659AB80f012", "relayerAddress": "0x63606C4011e97a73BCd844Cde6a38D45a728BC0E",
"isRegistered": true, "isRegistered": true,
"owner": "0xa0109274F53609f6Be97ec5f3052C659AB80f012", "owner": "0x63606C4011e97a73BCd844Cde6a38D45a728BC0E",
"stakeBalance": "4989.637826137906607638", "stakeBalance": "4476.543684932880020592",
"hostnames": { "hostnames": {
"1": "torn.relayersdao.finance", "1": "mainnet-tornado.appleworld.club",
"56": "bsc.relayersdao.finance", "56": "bsc-tornado.appleworld.club"
"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"
} }
}, },
{ {
@ -290,67 +98,286 @@
} }
}, },
{ {
"ensName": "on-sale.eth", "ensName": "reslayer.eth",
"relayerAddress": "0x63606C4011e97a73BCd844Cde6a38D45a728BC0E", "relayerAddress": "0x7Ba6781620c91676B070D319E7E894BFd4A9eC81",
"isRegistered": true, "isRegistered": true,
"owner": "0x63606C4011e97a73BCd844Cde6a38D45a728BC0E", "owner": "0x7Ba6781620c91676B070D319E7E894BFd4A9eC81",
"stakeBalance": "4476.543684932880020592", "stakeBalance": "879.305690438201312145",
"hostnames": { "hostnames": {
"1": "mainnet-tornado.appleworld.club", "1": "mainnet-tornado.reslayer.xyz",
"56": "bsc-tornado.appleworld.club" "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": "relayernews.eth", "ensName": "0xtorn.eth",
"relayerAddress": "0x6289C8a70EE2Ed6914834CaEa431F9a82c7eAf70", "relayerAddress": "0x9Ffbd3f9eE795A4fDa880ED553A2A4BD6D45CE5B",
"isRegistered": true, "isRegistered": true,
"owner": "0x6289C8a70EE2Ed6914834CaEa431F9a82c7eAf70", "owner": "0x9Ffbd3f9eE795A4fDa880ED553A2A4BD6D45CE5B",
"stakeBalance": "1661.181918638614466424", "stakeBalance": "4627.036617270139345308",
"hostnames": { "hostnames": {
"1": "mainnet-tornado.relayernews.xyz", "1": "mainnet.al1n.cc",
"56": "bsc-tornado.relayernews.xyz" "56": "bsc-tornado.al1n.cc"
} }
}, },
{ {
"ensName": "lowcost.eth", "ensName": "wetez.eth",
"relayerAddress": "0x28907F21F43B419F34226d6f10aCbCf1832b1D4d", "relayerAddress": "0xe6184DA55174Cc0263a17eA2fc24E48511766505",
"isRegistered": true, "isRegistered": true,
"owner": "0x28907F21F43B419F34226d6f10aCbCf1832b1D4d", "owner": "0xe6184DA55174Cc0263a17eA2fc24E48511766505",
"stakeBalance": "500.279638085962965981", "stakeBalance": "567.980734786905511868",
"hostnames": { "hostnames": {
"1": "mainnet-tornado.low-fee.xyz", "1": "tornado-1.wetez.io"
"56": "bsc-tornado.low-fee.xyz",
"137": "polygon-tornado.low-fee.xyz",
"43114": "avalanche-tornado.low-fee.xyz"
} }
}, },
{ {
"ensName": "cheap-relayer.eth", "ensName": "0xproxy.eth",
"relayerAddress": "0x076D4E32C6A5D888fC4658281539c94E778C796d", "relayerAddress": "0x08657a1f4C1F06d657F31767831421EE7FaDf549",
"isRegistered": true, "isRegistered": true,
"owner": "0x076D4E32C6A5D888fC4658281539c94E778C796d", "owner": "0x08657a1f4C1F06d657F31767831421EE7FaDf549",
"stakeBalance": "500.878420081833044818", "stakeBalance": "705.605817336537209483",
"hostnames": { "hostnames": {
"1": "mainnet-tornado.cheap-relayer.xyz", "1": "mainnet.0x0relayer.xyz",
"56": "bsc-tornado.cheap-relayer.xyz", "56": "bsc.0x0relayer.xyz",
"137": "polygon-tornado.cheap-relayer.xyz", "137": "polygon.0x0relayer.xyz"
"43114": "avalanche-tornado.cheap-relayer.xyz"
} }
}, },
{ {
"ensName": "therelayer.eth", "ensName": "torn-eth.eth",
"relayerAddress": "0xA0F0287683E820FF4211e67C03cf46a87431f4E1", "relayerAddress": "0x42FecB4137aFF76E0E85702ff4F339DbFe6D859E",
"isRegistered": true, "isRegistered": true,
"owner": "0xA0F0287683E820FF4211e67C03cf46a87431f4E1", "owner": "0x42FecB4137aFF76E0E85702ff4F339DbFe6D859E",
"stakeBalance": "1335.888771359625809238", "stakeBalance": "978.62598484549460861",
"hostnames": { "hostnames": {
"1": "mainnet.therelayer.xyz", "1": "mainnet-tornado.50swap.com"
"10": "optimism.therelayer.xyz", }
"56": "bsc.therelayer.xyz", },
"100": "xdai.therelayer.xyz", {
"137": "polygon.therelayer.xyz", "ensName": "shadow-out.eth",
"42161": "arbitrum.therelayer.xyz", "relayerAddress": "0x9Ee26a4bFd731E8e742B65bF955814EADdd7F151",
"43114": "avalanche.therelayer.xyz" "isRegistered": true,
"owner": "0x9Ee26a4bFd731E8e742B65bF955814EADdd7F151",
"stakeBalance": "3571.639136672079169166",
"hostnames": {
"1": "livetobecomeavillain",
"56": "justarandomdude",
"100": "everythingisburning"
}
},
{
"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": "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": "secure-relay.eth",
"relayerAddress": "0x1036AF02bCDb2e3A4db2d3D40b29e5054EDc79BA",
"isRegistered": true,
"owner": "0x1036AF02bCDb2e3A4db2d3D40b29e5054EDc79BA",
"stakeBalance": "6751.661507930994067422",
"hostnames": {
"1": "torn-relayer.duckdns.org"
}
},
{
"ensName": "relayer007.eth",
"relayerAddress": "0xa0109274F53609f6Be97ec5f3052C659AB80f012",
"isRegistered": true,
"owner": "0xa0109274F53609f6Be97ec5f3052C659AB80f012",
"stakeBalance": "2075.677151387681021207",
"hostnames": {
"1": "torn.relayersdao.finance",
"56": "bsc.relayersdao.finance",
"137": "matic.relayersdao.finance"
}
},
{
"ensName": "reltor.eth",
"relayerAddress": "0x4750BCfcC340AA4B31be7e71fa072716d28c29C5",
"isRegistered": true,
"owner": "0x4750BCfcC340AA4B31be7e71fa072716d28c29C5",
"stakeBalance": "17078.896444585792890283",
"hostnames": {
"1": "eth.reltor.su",
"56": "binance.reltor.su",
"137": "polygon.reltor.su"
}
},
{
"ensName": "t-relayer.eth",
"relayerAddress": "0x000000Cd6521Ed1a65FAe0678eA15aF4EEAD74fe",
"isRegistered": true,
"owner": "0x000000Cd6521Ed1a65FAe0678eA15aF4EEAD74fe",
"stakeBalance": "9393.81613250700489948",
"hostnames": {
"1": "eth.t-relayer.com",
"56": "bsc.t-relayer.com"
}
},
{
"ensName": "default-relayer.eth",
"relayerAddress": "0x5555555731006f71f121144534Ca7C8799F66AA3",
"isRegistered": true,
"owner": "0x5555555731006f71f121144534Ca7C8799F66AA3",
"stakeBalance": "12244.203047120053584442",
"hostnames": {
"1": "eth.default-relayer.com",
"56": "bsc.default-relayer.com"
}
},
{
"ensName": "relayer-secure.eth",
"relayerAddress": "0xCEdac436cEA98E93F471331eCC693fF41D730921",
"isRegistered": true,
"owner": "0xCEdac436cEA98E93F471331eCC693fF41D730921",
"stakeBalance": "548.198082306127582623",
"hostnames": {
"1": "relsecc-mainnet.moon-relayer.app"
}
},
{
"ensName": "0xgm777.eth",
"relayerAddress": "0x94596B6A626392F5D972D6CC4D929a42c2f0008c",
"isRegistered": true,
"owner": "0x94596B6A626392F5D972D6CC4D929a42c2f0008c",
"stakeBalance": "1649.22629774180421325",
"hostnames": {
"1": "main.gm777.xyz",
"56": "bsc.gm777.xyz",
"42161": "arb.gm777.xyz"
}
},
{
"ensName": "k-relayer.eth",
"relayerAddress": "0xC49415493eB3Ec64a0F13D8AA5056f1CfC4ce35c",
"isRegistered": true,
"owner": "0xC49415493eB3Ec64a0F13D8AA5056f1CfC4ce35c",
"stakeBalance": "2392.026618435010858225",
"hostnames": {
"1": "black-hardy.com",
"56": "bsc.black-hardy.com"
}
},
{
"ensName": "tornxdo.eth",
"relayerAddress": "0xB399aa4c2F1678f72529Cd125F82cEA2c2a823eD",
"isRegistered": true,
"owner": "0xB399aa4c2F1678f72529Cd125F82cEA2c2a823eD",
"stakeBalance": "983.310689667160962345",
"hostnames": {
"1": "tornado.evmjunkie.xyz"
}
},
{
"ensName": "torrelayer.eth",
"relayerAddress": "0x2Ee39Ff05643bC7cc9ed31B71e142429044A425C",
"isRegistered": true,
"owner": "0x2Ee39Ff05643bC7cc9ed31B71e142429044A425C",
"stakeBalance": "4150.327987173762878437",
"hostnames": {
"1": "tornima.xyz",
"56": "binance.tornima.xyz"
}
},
{
"ensName": "torn-city.eth",
"relayerAddress": "0xd04e9f0945DEA8373D882C730e2c93a74B591796",
"isRegistered": true,
"owner": "0xd04e9f0945DEA8373D882C730e2c93a74B591796",
"stakeBalance": "6636.564618899564311691",
"hostnames": {
"1": "torn-city.com",
"56": "bsc.torn-city.com"
}
},
{
"ensName": "crelayer.eth",
"relayerAddress": "0x180c58B7305152357142b33Eea94cBB152058B61",
"isRegistered": true,
"owner": "0x180c58B7305152357142b33Eea94cBB152058B61",
"stakeBalance": "1460.389956347917729137",
"hostnames": {
"1": "eth.crelayer.xyz",
"56": "bsc.crelayer.xyz"
}
},
{
"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": "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": "quick-relayer.eth",
"relayerAddress": "0x187541D7D312F742040f270d0221B4Fe577934B0",
"isRegistered": true,
"owner": "0x187541D7D312F742040f270d0221B4Fe577934B0",
"stakeBalance": "2931.033250737658918569",
"hostnames": {
"1": "quick-relayer.xyz"
}
},
{
"ensName": "okrelayer.eth",
"relayerAddress": "0x0e9D9a828247F5eed7f6D31D213A39805De52441",
"isRegistered": true,
"owner": "0x0e9D9a828247F5eed7f6D31D213A39805De52441",
"stakeBalance": "4668.726167448982243314",
"hostnames": {
"1": "okrelayer.xyz",
"56": "binance.okrelayer.xyz",
"137": "polygon.okrelayer.xyz",
"42161": "arb.okrelayer.xyz"
}
},
{
"ensName": "s-relayer.eth",
"relayerAddress": "0xc6398b4e8B60720051ed33f5C5a692f9785f5580",
"isRegistered": true,
"owner": "0xc6398b4e8B60720051ed33f5C5a692f9785f5580",
"stakeBalance": "5000.0",
"hostnames": {
"1": "s-relayer.xyz"
} }
} }
] ]

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More