Tornado CLI 1.0.9-alpha

* improve event sync
* use latest core deps
This commit is contained in:
Tornado Contrib 2024-09-25 08:40:15 +00:00
parent 37ce302ca5
commit 4c9fc48ad5
Signed by: tornadocontrib
GPG Key ID: 60B4DF1A076C64B1
6 changed files with 185 additions and 187 deletions

142
dist/cli.js vendored

@ -176375,6 +176375,8 @@ const defaultConfig = {
gasLimit: 7e5 gasLimit: 7e5
} }
}, },
// Inactive tokens to filter from schema verification and syncing events
disabledTokens: ["cdai", "usdt", "usdc"],
relayerEnsSubdomain: "mainnet-tornado", relayerEnsSubdomain: "mainnet-tornado",
pollInterval: 15, pollInterval: 15,
constants: { constants: {
@ -176832,9 +176834,16 @@ function getConfig(netId) {
} }
return chainConfig; return chainConfig;
} }
function getInstanceByAddress({ netId, address }) { function getActiveTokens(config) {
const { tokens } = getConfig(netId); const { tokens, disabledTokens } = config;
return Object.keys(tokens).filter((t) => !(disabledTokens == null ? void 0 : disabledTokens.includes(t)));
}
function getInstanceByAddress(config, address) {
const { tokens, disabledTokens } = config;
for (const [currency, { instanceAddress }] of Object.entries(tokens)) { for (const [currency, { instanceAddress }] of Object.entries(tokens)) {
if (disabledTokens == null ? void 0 : disabledTokens.includes(currency)) {
continue;
}
for (const [amount, instance] of Object.entries(instanceAddress)) { for (const [amount, instance] of Object.entries(instanceAddress)) {
if (instance === address) { if (instance === address) {
return { return {
@ -176845,10 +176854,6 @@ function getInstanceByAddress({ netId, address }) {
} }
} }
} }
function getSubdomains() {
const allConfig = getNetworkConfig();
return enabledChains.map((chain) => allConfig[chain].relayerEnsSubdomain);
}
function getRelayerEnsSubdomains() { function getRelayerEnsSubdomains() {
const allConfig = getNetworkConfig(); const allConfig = getNetworkConfig();
return enabledChains.reduce((acc, chain) => { return enabledChains.reduce((acc, chain) => {
@ -176888,7 +176893,7 @@ const statusSchema = {
required: ["rewardAccount", "instances", "netId", "tornadoServiceFee", "version", "health"] required: ["rewardAccount", "instances", "netId", "tornadoServiceFee", "version", "health"]
}; };
function getStatusSchema(netId, config) { function getStatusSchema(netId, config) {
const { tokens, optionalTokens = [], nativeCurrency } = config; const { tokens, optionalTokens, disabledTokens, nativeCurrency } = config;
const schema = JSON.parse(JSON.stringify(statusSchema)); const schema = JSON.parse(JSON.stringify(statusSchema));
const instances = Object.keys(tokens).reduce( const instances = Object.keys(tokens).reduce(
(acc, token) => { (acc, token) => {
@ -176919,7 +176924,7 @@ function getStatusSchema(netId, config) {
instanceProperties.properties.symbol = { enum: [symbol] }; instanceProperties.properties.symbol = { enum: [symbol] };
} }
acc.properties[token] = instanceProperties; acc.properties[token] = instanceProperties;
if (!optionalTokens.includes(token)) { if (!(optionalTokens == null ? void 0 : optionalTokens.includes(token)) && !(disabledTokens == null ? void 0 : disabledTokens.includes(token))) {
acc.required.push(token); acc.required.push(token);
} }
return acc; return acc;
@ -177023,18 +177028,6 @@ var __async$9 = (__this, __arguments, generator) => {
const MIN_FEE = 0.1; const MIN_FEE = 0.1;
const MAX_FEE = 0.6; const MAX_FEE = 0.6;
const MIN_STAKE_BALANCE = parseEther("500"); const MIN_STAKE_BALANCE = parseEther("500");
const semVerRegex = new RegExp("^(?<major>0|[1-9]\\d*)\\.(?<minor>0|[1-9]\\d*)\\.(?<patch>0|[1-9]\\d*)(?:-(?<prerelease>(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+(?<buildmetadata>[0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$");
function parseSemanticVersion(version) {
const { groups } = semVerRegex.exec(version);
return groups;
}
function isRelayerUpdated(relayerVersion, netId) {
const { major, patch, prerelease } = parseSemanticVersion(relayerVersion);
const requiredMajor = netId === NetId.MAINNET ? "4" : "5";
const isUpdatedMajor = major === requiredMajor;
if (prerelease) return false;
return isUpdatedMajor && (Number(patch) >= 5 || netId !== NetId.MAINNET);
}
function calculateScore({ stakeBalance, tornadoServiceFee }) { function calculateScore({ stakeBalance, tornadoServiceFee }) {
if (tornadoServiceFee < MIN_FEE) { if (tornadoServiceFee < MIN_FEE) {
tornadoServiceFee = MIN_FEE; tornadoServiceFee = MIN_FEE;
@ -177106,9 +177099,6 @@ class RelayerClient {
if (relayerAddress && this.netId === NetId.MAINNET && status.rewardAccount !== relayerAddress) { if (relayerAddress && this.netId === NetId.MAINNET && status.rewardAccount !== relayerAddress) {
throw new Error("The Relayer reward address must match registered address"); throw new Error("The Relayer reward address must match registered address");
} }
if (!isRelayerUpdated(status.version, this.netId)) {
throw new Error("Outdated version.");
}
return status; return status;
}); });
} }
@ -181125,7 +181115,7 @@ function calculateSnarkProof(input, circuit, provingKey) {
;// CONCATENATED MODULE: ./package.json ;// CONCATENATED MODULE: ./package.json
const package_namespaceObject = /*#__PURE__*/JSON.parse('{"rE":"1.0.8-alpha","h_":"Modern Toolsets for Privacy Pools on Ethereum"}'); const package_namespaceObject = /*#__PURE__*/JSON.parse('{"rE":"1.0.9-alpha","h_":"Modern Toolsets for Privacy Pools on Ethereum"}');
var package_namespaceObject_0 = /*#__PURE__*/__webpack_require__.t(package_namespaceObject, 2); var package_namespaceObject_0 = /*#__PURE__*/__webpack_require__.t(package_namespaceObject, 2);
;// CONCATENATED MODULE: external "module" ;// CONCATENATED MODULE: external "module"
const external_module_namespaceObject = require("module"); const external_module_namespaceObject = require("module");
@ -184033,7 +184023,10 @@ class NodeTornadoService extends BaseTornadoService {
deployedBlock, deployedBlock,
fetchDataOptions, fetchDataOptions,
cacheDirectory, cacheDirectory,
userDirectory userDirectory,
nativeCurrency,
merkleTreeService,
treeCache
}) { }) {
super({ super({
netId, netId,
@ -184049,6 +184042,9 @@ class NodeTornadoService extends BaseTornadoService {
}); });
this.cacheDirectory = cacheDirectory; this.cacheDirectory = cacheDirectory;
this.userDirectory = userDirectory; this.userDirectory = userDirectory;
this.nativeCurrency = nativeCurrency;
this.merkleTreeService = merkleTreeService;
this.treeCache = treeCache;
} }
updateEventProgress({ type, fromBlock, toBlock, count }) { updateEventProgress({ type, fromBlock, toBlock, count }) {
if (toBlock) { if (toBlock) {
@ -184160,6 +184156,14 @@ class NodeTornadoService extends BaseTornadoService {
); );
console.log(eventTable.toString() + "\n"); console.log(eventTable.toString() + "\n");
if (this.userDirectory) { if (this.userDirectory) {
if (this.merkleTreeService) {
const tree = yield this.merkleTreeService.verifyTree(events);
if (this.currency === this.nativeCurrency && this.treeCache) {
yield this.treeCache.createTree(events, tree);
console.log(`${this.getInstanceName()}: Updated tree cache with root ${toFixedHex(BigInt(tree.root))}
`);
}
}
yield saveUserFile({ yield saveUserFile({
fileName: instanceName + ".json", fileName: instanceName + ".json",
userDirectory: this.userDirectory, userDirectory: this.userDirectory,
@ -185038,12 +185042,11 @@ var program_async = (__this, __arguments, generator) => {
const EXEC_NAME = "tornado-cli"; const EXEC_NAME = "tornado-cli";
const INACTIVE_TOKENS = ["cdai", "usdc", "usdt"];
const DEFAULT_GAS_LIMIT = Number((external_process_default()).env.DEFAULT_GAS_LIMIT) || 6e5; const DEFAULT_GAS_LIMIT = Number((external_process_default()).env.DEFAULT_GAS_LIMIT) || 6e5;
const RELAYER_NETWORK = Number((external_process_default()).env.RELAYER_NETWORK) || NetId.MAINNET; const RELAYER_NETWORK = Number((external_process_default()).env.RELAYER_NETWORK) || NetId.MAINNET;
const STATIC_DIR = (external_process_default()).env.CACHE_DIR || external_path_default().join(__dirname, "../static"); const STATIC_DIR = (external_process_default()).env.CACHE_DIR || external_path_default().join(__dirname, "../static");
const EVENTS_DIR = external_path_default().join(STATIC_DIR, "./events"); const EVENTS_DIR = external_path_default().join(STATIC_DIR, "./events");
const MERKLE_WORKER_PATH = (external_process_default()).env.DISABLE_MERKLE_WORKER === "true" ? void 0 : external_path_default().join(STATIC_DIR, "./merkleTreeWorker.js"); const merkleWorkerPath = external_path_default().join(STATIC_DIR, "./merkleTreeWorker.js");
const USER_DIR = (external_process_default()).env.USER_DIR || "."; const USER_DIR = (external_process_default()).env.USER_DIR || ".";
const SAVED_DIR = external_path_default().join(USER_DIR, "./events"); const SAVED_DIR = external_path_default().join(USER_DIR, "./events");
const SAVED_TREE_DIR = external_path_default().join(USER_DIR, "./trees"); const SAVED_TREE_DIR = external_path_default().join(USER_DIR, "./trees");
@ -185185,7 +185188,6 @@ function getProgramRelayer(_0) {
}, },
ethConfig ethConfig
); );
const relayerEnsSubdomains = getRelayerEnsSubdomains();
const registryService = new NodeRegistryService({ const registryService = new NodeRegistryService({
netId: RELAYER_NETWORK, netId: RELAYER_NETWORK,
provider, provider,
@ -185193,7 +185195,7 @@ function getProgramRelayer(_0) {
subgraphName: registrySubgraph, subgraphName: registrySubgraph,
RelayerRegistry: RelayerRegistry__factory.connect(registryContract, provider), RelayerRegistry: RelayerRegistry__factory.connect(registryContract, provider),
Aggregator: Aggregator__factory.connect(aggregatorContract, provider), Aggregator: Aggregator__factory.connect(aggregatorContract, provider),
relayerEnsSubdomains, relayerEnsSubdomains: getRelayerEnsSubdomains(),
deployedBlock: REGISTRY_BLOCK, deployedBlock: REGISTRY_BLOCK,
fetchDataOptions: fetchDataOptions2, fetchDataOptions: fetchDataOptions2,
cacheDirectory: EVENTS_DIR, cacheDirectory: EVENTS_DIR,
@ -185595,7 +185597,8 @@ function tornadoProgram() {
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2, fetchDataOptions: fetchDataOptions2,
cacheDirectory: EVENTS_DIR, cacheDirectory: EVENTS_DIR,
userDirectory: SAVED_DIR userDirectory: SAVED_DIR,
nativeCurrency
}; };
const depositsService = new NodeTornadoService(program_spreadProps(program_spreadValues({}, TornadoServiceConstructor), { const depositsService = new NodeTornadoService(program_spreadProps(program_spreadValues({}, TornadoServiceConstructor), {
type: "Deposit" type: "Deposit"
@ -185608,10 +185611,10 @@ function tornadoProgram() {
amount, amount,
currency, currency,
Tornado, Tornado,
merkleWorkerPath: MERKLE_WORKER_PATH merkleWorkerPath
}); });
const depositEvents = (yield depositsService.updateEvents()).events; const depositEvents = (yield depositsService.updateEvents()).events;
const depositTreePromise = MERKLE_WORKER_PATH ? merkleTreeService.verifyTree(depositEvents) : yield merkleTreeService.verifyTree(depositEvents); const depositTreePromise = merkleTreeService.verifyTree(depositEvents);
const withdrawalEvents = (yield withdrawalsService.updateEvents()).events; const withdrawalEvents = (yield withdrawalsService.updateEvents()).events;
const depositEvent = depositEvents.find(({ commitment }) => commitment === commitmentHex); const depositEvent = depositEvents.find(({ commitment }) => commitment === commitmentHex);
const withdrawalEvent = withdrawalEvents.find(({ nullifierHash }) => nullifierHash === nullifierHex); const withdrawalEvent = withdrawalEvents.find(({ nullifierHash }) => nullifierHash === nullifierHex);
@ -185808,6 +185811,7 @@ function tornadoProgram() {
const { const {
tornadoSubgraph, tornadoSubgraph,
deployedBlock, deployedBlock,
nativeCurrency,
tokens: { [currency]: currencyConfig } tokens: { [currency]: currencyConfig }
} = config; } = config;
const { const {
@ -185830,27 +185834,24 @@ function tornadoProgram() {
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2, fetchDataOptions: fetchDataOptions2,
cacheDirectory: EVENTS_DIR, cacheDirectory: EVENTS_DIR,
userDirectory: SAVED_DIR userDirectory: SAVED_DIR,
nativeCurrency
}; };
const depositsService = new NodeTornadoService(program_spreadProps(program_spreadValues({}, TornadoServiceConstructor), { const depositsService = new NodeTornadoService(program_spreadProps(program_spreadValues({}, TornadoServiceConstructor), {
type: "Deposit" type: "Deposit",
merkleTreeService: new MerkleTreeService({
netId,
amount,
currency,
Tornado,
merkleWorkerPath
})
})); }));
const withdrawalsService = new NodeTornadoService(program_spreadProps(program_spreadValues({}, TornadoServiceConstructor), { const withdrawalsService = new NodeTornadoService(program_spreadProps(program_spreadValues({}, TornadoServiceConstructor), {
type: "Withdrawal" type: "Withdrawal"
})); }));
const merkleTreeService = new MerkleTreeService({
netId,
amount,
currency,
Tornado,
merkleWorkerPath: MERKLE_WORKER_PATH
});
const depositEvents = (yield depositsService.updateEvents()).events; const depositEvents = (yield depositsService.updateEvents()).events;
const depositTreePromise = MERKLE_WORKER_PATH ? merkleTreeService.verifyTree(depositEvents) : yield merkleTreeService.verifyTree(depositEvents); const withdrawalEvents = (yield withdrawalsService.updateEvents()).events;
const [withdrawalEvents] = yield Promise.all([
withdrawalsService.updateEvents().then(({ events }) => events),
depositTreePromise
]);
const depositEvent = depositEvents.find(({ commitment }) => commitment === commitmentHex); const depositEvent = depositEvents.find(({ commitment }) => commitment === commitmentHex);
const withdrawalEvent = withdrawalEvents.find(({ nullifierHash }) => nullifierHash === nullifierHex); const withdrawalEvent = withdrawalEvents.find(({ nullifierHash }) => nullifierHash === nullifierHex);
const complianceTable = new (cli_table3_default())(); const complianceTable = new (cli_table3_default())();
@ -185930,7 +185931,6 @@ function tornadoProgram() {
yield governanceService.updateEvents(); yield governanceService.updateEvents();
} }
if (registryContract && aggregatorContract) { if (registryContract && aggregatorContract) {
const relayerEnsSubdomains = getRelayerEnsSubdomains();
const registryService = new NodeRegistryService({ const registryService = new NodeRegistryService({
netId, netId,
provider, provider,
@ -185938,7 +185938,7 @@ function tornadoProgram() {
subgraphName: registrySubgraph, subgraphName: registrySubgraph,
RelayerRegistry: RelayerRegistry__factory.connect(registryContract, provider), RelayerRegistry: RelayerRegistry__factory.connect(registryContract, provider),
Aggregator: Aggregator__factory.connect(aggregatorContract, provider), Aggregator: Aggregator__factory.connect(aggregatorContract, provider),
relayerEnsSubdomains, relayerEnsSubdomains: getRelayerEnsSubdomains(),
deployedBlock: REGISTRY_BLOCK, deployedBlock: REGISTRY_BLOCK,
fetchDataOptions: fetchDataOptions2, fetchDataOptions: fetchDataOptions2,
cacheDirectory: EVENTS_DIR, cacheDirectory: EVENTS_DIR,
@ -185970,11 +185970,8 @@ function tornadoProgram() {
userDirectory: SAVED_DIR userDirectory: SAVED_DIR
}); });
yield encryptedNotesService.updateEvents(); yield encryptedNotesService.updateEvents();
const currencies = currencyOpts ? [currencyOpts.toLowerCase()] : Object.keys(tokens); const currencies = currencyOpts ? [currencyOpts.toLowerCase()] : getActiveTokens(config);
for (const currency of currencies) { for (const currency of currencies) {
if (INACTIVE_TOKENS.includes(currency)) {
continue;
}
const currencyConfig = tokens[currency]; const currencyConfig = tokens[currency];
const amounts = Object.keys(currencyConfig.instanceAddress); const amounts = Object.keys(currencyConfig.instanceAddress);
for (const amount of amounts) { for (const amount of amounts) {
@ -185991,33 +185988,30 @@ function tornadoProgram() {
deployedBlock, deployedBlock,
fetchDataOptions: fetchDataOptions2, fetchDataOptions: fetchDataOptions2,
cacheDirectory: EVENTS_DIR, cacheDirectory: EVENTS_DIR,
userDirectory: SAVED_DIR userDirectory: SAVED_DIR,
nativeCurrency
}; };
const depositsService = new NodeTornadoService(program_spreadProps(program_spreadValues({}, TornadoServiceConstructor), { const depositsService = new NodeTornadoService(program_spreadProps(program_spreadValues({}, TornadoServiceConstructor), {
type: "Deposit" type: "Deposit",
merkleTreeService: new MerkleTreeService({
netId,
amount,
currency,
Tornado,
merkleWorkerPath
}),
treeCache: new TreeCache({
netId,
amount,
currency,
userDirectory: SAVED_TREE_DIR
})
})); }));
const withdrawalsService = new NodeTornadoService(program_spreadProps(program_spreadValues({}, TornadoServiceConstructor), { const withdrawalsService = new NodeTornadoService(program_spreadProps(program_spreadValues({}, TornadoServiceConstructor), {
type: "Withdrawal" type: "Withdrawal"
})); }));
const merkleTreeService = new MerkleTreeService({ yield depositsService.updateEvents();
netId, yield withdrawalsService.updateEvents();
amount,
currency,
Tornado,
merkleWorkerPath: MERKLE_WORKER_PATH
});
const treeCache = new TreeCache({
netId,
amount,
currency,
userDirectory: SAVED_TREE_DIR
});
const depositEvents = (yield depositsService.updateEvents()).events;
const depositTreePromise = MERKLE_WORKER_PATH ? merkleTreeService.verifyTree(depositEvents) : yield merkleTreeService.verifyTree(depositEvents);
const [tree] = yield Promise.all([depositTreePromise, withdrawalsService.updateEvents()]);
if (nativeCurrency === currency) {
yield treeCache.createTree(depositEvents, tree);
}
} }
} }
} }
@ -186203,7 +186197,7 @@ function tornadoProgram() {
[{ colSpan: 2, content: `Account key: ${accountKey}`, hAlign: "center" }], [{ colSpan: 2, content: `Account key: ${accountKey}`, hAlign: "center" }],
["blockNumber", "note"].map((content) => ({ content: lib_default().red.bold(content) })), ["blockNumber", "note"].map((content) => ({ content: lib_default().red.bold(content) })),
...noteAccount.decryptNotes(encryptedNoteEvents).map(({ blockNumber, address, noteHex }) => { ...noteAccount.decryptNotes(encryptedNoteEvents).map(({ blockNumber, address, noteHex }) => {
const { amount, currency } = getInstanceByAddress({ netId, address }); const { amount, currency } = getInstanceByAddress(config, address) || {};
return [blockNumber, `tornado-${currency}-${amount}-${netId}-${noteHex}`]; return [blockNumber, `tornado-${currency}-${amount}-${netId}-${noteHex}`];
}) })
); );

@ -1,13 +1,20 @@
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, CachedRelayers } from '@tornado/core';
import type { BaseEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, RegistersEvents, AllGovernanceEvents, EchoEvents } from '@tornado/core'; import type { BaseEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, RegistersEvents, AllGovernanceEvents, EchoEvents, MerkleTreeService } from '@tornado/core';
import { TreeCache } from './treeCache';
export type NodeTornadoServiceConstructor = BaseTornadoServiceConstructor & { export type NodeTornadoServiceConstructor = BaseTornadoServiceConstructor & {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: string; userDirectory: string;
nativeCurrency: string;
merkleTreeService?: MerkleTreeService;
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;
merkleTreeService?: MerkleTreeService;
treeCache?: TreeCache;
constructor({ netId, provider, graphApi, subgraphName, Tornado, type, amount, currency, deployedBlock, fetchDataOptions, cacheDirectory, userDirectory, nativeCurrency, merkleTreeService, treeCache, }: 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;
@ -17,12 +24,12 @@ export declare class NodeTornadoService extends BaseTornadoService {
saveEvents({ events, lastBlock }: BaseEvents<DepositsEvents | WithdrawalsEvents>): Promise<void>; saveEvents({ events, lastBlock }: BaseEvents<DepositsEvents | WithdrawalsEvents>): Promise<void>;
} }
export type NodeEchoServiceConstructor = BaseEchoServiceConstructor & { export type NodeEchoServiceConstructor = BaseEchoServiceConstructor & {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: 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({ netId, provider, graphApi, subgraphName, Echoer, deployedBlock, fetchDataOptions, cacheDirectory, userDirectory, }: 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; updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
@ -31,12 +38,12 @@ export declare class NodeEchoService extends BaseEchoService {
saveEvents({ events, lastBlock }: BaseEvents<EchoEvents>): Promise<void>; saveEvents({ events, lastBlock }: BaseEvents<EchoEvents>): Promise<void>;
} }
export type NodeEncryptedNotesServiceConstructor = BaseEncryptedNotesServiceConstructor & { export type NodeEncryptedNotesServiceConstructor = BaseEncryptedNotesServiceConstructor & {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: 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({ netId, provider, graphApi, subgraphName, Router, deployedBlock, fetchDataOptions, cacheDirectory, userDirectory, }: 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; updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
@ -45,12 +52,12 @@ export declare class NodeEncryptedNotesService extends BaseEncryptedNotesService
saveEvents({ events, lastBlock }: BaseEvents<EncryptedNotesEvents>): Promise<void>; saveEvents({ events, lastBlock }: BaseEvents<EncryptedNotesEvents>): Promise<void>;
} }
export type NodeGovernanceServiceConstructor = BaseGovernanceServiceConstructor & { export type NodeGovernanceServiceConstructor = BaseGovernanceServiceConstructor & {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: 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({ netId, provider, graphApi, subgraphName, Governance, deployedBlock, fetchDataOptions, cacheDirectory, userDirectory, }: 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; updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
@ -60,12 +67,12 @@ export declare class NodeGovernanceService extends BaseGovernanceService {
saveEvents({ events, lastBlock }: BaseEvents<AllGovernanceEvents>): Promise<void>; saveEvents({ events, lastBlock }: BaseEvents<AllGovernanceEvents>): Promise<void>;
} }
export type NodeRegistryServiceConstructor = BaseRegistryServiceConstructor & { export type NodeRegistryServiceConstructor = BaseRegistryServiceConstructor & {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: 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({ netId, provider, graphApi, subgraphName, RelayerRegistry, Aggregator, relayerEnsSubdomains, deployedBlock, fetchDataOptions, cacheDirectory, userDirectory, }: 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; updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;

@ -1,6 +1,6 @@
{ {
"name": "@tornado/cli", "name": "@tornado/cli",
"version": "1.0.8-alpha", "version": "1.0.9-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",
@ -51,7 +51,7 @@
"optionalDependencies": {}, "optionalDependencies": {},
"devDependencies": { "devDependencies": {
"@colors/colors": "1.5.0", "@colors/colors": "1.5.0",
"@tornado/core": "git+https://git.tornado.ws/tornadocontrib/tornado-core.git#d0b032d7bef06de61872ba7ad07b769b9b1d9717", "@tornado/core": "git+https://git.tornado.ws/tornadocontrib/tornado-core.git#f7fdf7db0a813ae2193f9864e212d68dc840c0d7",
"@typechain/ethers-v6": "^0.5.1", "@typechain/ethers-v6": "^0.5.1",
"@types/figlet": "^1.5.8", "@types/figlet": "^1.5.8",
"@typescript-eslint/eslint-plugin": "^8.6.0", "@typescript-eslint/eslint-plugin": "^8.6.0",

@ -67,6 +67,7 @@ import {
getSupportedInstances, getSupportedInstances,
initGroth16, initGroth16,
getRelayerEnsSubdomains, getRelayerEnsSubdomains,
getActiveTokens,
} from '@tornado/core'; } from '@tornado/core';
import * as packageJson from '../package.json'; import * as packageJson from '../package.json';
import { import {
@ -87,9 +88,6 @@ import {
const EXEC_NAME = 'tornado-cli'; const EXEC_NAME = 'tornado-cli';
// Inactive tokens to filter from syncing (Either they have no activity for more than a year, should be filtered from event syncs and withdrawals)
const INACTIVE_TOKENS: string[] = ['cdai', 'usdc', 'usdt'];
/** /**
* Static variables, shouldn't be modified by env unless you know what they are doing * Static variables, shouldn't be modified by env unless you know what they are doing
*/ */
@ -100,8 +98,7 @@ const RELAYER_NETWORK = Number(process.env.RELAYER_NETWORK) || NetId.MAINNET;
// Where cached events, trees, circuits, and key is saved // Where cached events, trees, circuits, and key is saved
const STATIC_DIR = process.env.CACHE_DIR || path.join(__dirname, '../static'); const STATIC_DIR = process.env.CACHE_DIR || path.join(__dirname, '../static');
const EVENTS_DIR = path.join(STATIC_DIR, './events'); const EVENTS_DIR = path.join(STATIC_DIR, './events');
const MERKLE_WORKER_PATH = const merkleWorkerPath = path.join(STATIC_DIR, './merkleTreeWorker.js');
process.env.DISABLE_MERKLE_WORKER === 'true' ? undefined : path.join(STATIC_DIR, './merkleTreeWorker.js');
// Where we should backup notes and save events // Where we should backup notes and save events
const USER_DIR = process.env.USER_DIR || '.'; const USER_DIR = process.env.USER_DIR || '.';
@ -315,8 +312,6 @@ export async function getProgramRelayer({
ethConfig, ethConfig,
); );
const relayerEnsSubdomains = getRelayerEnsSubdomains();
const registryService = new NodeRegistryService({ const registryService = new NodeRegistryService({
netId: RELAYER_NETWORK, netId: RELAYER_NETWORK,
provider, provider,
@ -324,7 +319,7 @@ export async function getProgramRelayer({
subgraphName: registrySubgraph, subgraphName: registrySubgraph,
RelayerRegistry: RelayerRegistry__factory.connect(registryContract as string, provider), RelayerRegistry: RelayerRegistry__factory.connect(registryContract as string, provider),
Aggregator: Aggregator__factory.connect(aggregatorContract as string, provider), Aggregator: Aggregator__factory.connect(aggregatorContract as string, provider),
relayerEnsSubdomains, relayerEnsSubdomains: getRelayerEnsSubdomains(),
deployedBlock: REGISTRY_BLOCK, deployedBlock: REGISTRY_BLOCK,
fetchDataOptions, fetchDataOptions,
cacheDirectory: EVENTS_DIR, cacheDirectory: EVENTS_DIR,
@ -874,6 +869,7 @@ export function tornadoProgram() {
fetchDataOptions, fetchDataOptions,
cacheDirectory: EVENTS_DIR, cacheDirectory: EVENTS_DIR,
userDirectory: SAVED_DIR, userDirectory: SAVED_DIR,
nativeCurrency,
}; };
const depositsService = new NodeTornadoService({ const depositsService = new NodeTornadoService({
@ -891,15 +887,13 @@ export function tornadoProgram() {
amount, amount,
currency, currency,
Tornado, Tornado,
merkleWorkerPath: MERKLE_WORKER_PATH, merkleWorkerPath,
}); });
const depositEvents = (await depositsService.updateEvents()).events as DepositsEvents[]; const depositEvents = (await depositsService.updateEvents()).events as DepositsEvents[];
// If we have MERKLE_WORKER_PATH run worker at background otherwise resolve it here // Create tree using node workers which would spawn another dedicated thread to create trees
const depositTreePromise = MERKLE_WORKER_PATH const depositTreePromise = merkleTreeService.verifyTree(depositEvents);
? merkleTreeService.verifyTree(depositEvents)
: await merkleTreeService.verifyTree(depositEvents);
const withdrawalEvents = (await withdrawalsService.updateEvents()).events as WithdrawalsEvents[]; const withdrawalEvents = (await withdrawalsService.updateEvents()).events as WithdrawalsEvents[];
@ -1166,6 +1160,7 @@ export function tornadoProgram() {
const { const {
tornadoSubgraph, tornadoSubgraph,
deployedBlock, deployedBlock,
nativeCurrency,
tokens: { [currency]: currencyConfig }, tokens: { [currency]: currencyConfig },
} = config; } = config;
@ -1195,11 +1190,19 @@ export function tornadoProgram() {
fetchDataOptions, fetchDataOptions,
cacheDirectory: EVENTS_DIR, cacheDirectory: EVENTS_DIR,
userDirectory: SAVED_DIR, userDirectory: SAVED_DIR,
nativeCurrency,
}; };
const depositsService = new NodeTornadoService({ const depositsService = new NodeTornadoService({
...TornadoServiceConstructor, ...TornadoServiceConstructor,
type: 'Deposit', type: 'Deposit',
merkleTreeService: new MerkleTreeService({
netId,
amount,
currency,
Tornado,
merkleWorkerPath,
}),
}); });
const withdrawalsService = new NodeTornadoService({ const withdrawalsService = new NodeTornadoService({
@ -1207,25 +1210,9 @@ export function tornadoProgram() {
type: 'Withdrawal', type: 'Withdrawal',
}); });
const merkleTreeService = new MerkleTreeService({
netId,
amount,
currency,
Tornado,
merkleWorkerPath: MERKLE_WORKER_PATH,
});
const depositEvents = (await depositsService.updateEvents()).events as DepositsEvents[]; const depositEvents = (await depositsService.updateEvents()).events as DepositsEvents[];
// If we have MERKLE_WORKER_PATH run worker at background otherwise resolve it here const withdrawalEvents = (await withdrawalsService.updateEvents()).events as WithdrawalsEvents[];
const depositTreePromise = MERKLE_WORKER_PATH
? merkleTreeService.verifyTree(depositEvents)
: await merkleTreeService.verifyTree(depositEvents);
const [withdrawalEvents] = await Promise.all([
withdrawalsService.updateEvents().then(({ events }) => events as WithdrawalsEvents[]),
depositTreePromise,
]);
const depositEvent = depositEvents.find(({ commitment }) => commitment === commitmentHex); const depositEvent = depositEvents.find(({ commitment }) => commitment === commitmentHex);
@ -1327,8 +1314,6 @@ export function tornadoProgram() {
} }
if (registryContract && aggregatorContract) { if (registryContract && aggregatorContract) {
const relayerEnsSubdomains = getRelayerEnsSubdomains();
const registryService = new NodeRegistryService({ const registryService = new NodeRegistryService({
netId, netId,
provider, provider,
@ -1336,7 +1321,7 @@ export function tornadoProgram() {
subgraphName: registrySubgraph, subgraphName: registrySubgraph,
RelayerRegistry: RelayerRegistry__factory.connect(registryContract, provider), RelayerRegistry: RelayerRegistry__factory.connect(registryContract, provider),
Aggregator: Aggregator__factory.connect(aggregatorContract, provider), Aggregator: Aggregator__factory.connect(aggregatorContract, provider),
relayerEnsSubdomains, relayerEnsSubdomains: getRelayerEnsSubdomains(),
deployedBlock: REGISTRY_BLOCK, deployedBlock: REGISTRY_BLOCK,
fetchDataOptions, fetchDataOptions,
cacheDirectory: EVENTS_DIR, cacheDirectory: EVENTS_DIR,
@ -1374,14 +1359,9 @@ export function tornadoProgram() {
await encryptedNotesService.updateEvents(); await encryptedNotesService.updateEvents();
const currencies = currencyOpts ? [currencyOpts.toLowerCase()] : Object.keys(tokens); const currencies = currencyOpts ? [currencyOpts.toLowerCase()] : getActiveTokens(config);
for (const currency of currencies) { for (const currency of currencies) {
// Skip syncing inactive instances
if (INACTIVE_TOKENS.includes(currency)) {
continue;
}
const currencyConfig = tokens[currency]; const currencyConfig = tokens[currency];
// Now load the denominations and address // Now load the denominations and address
const amounts = Object.keys(currencyConfig.instanceAddress); const amounts = Object.keys(currencyConfig.instanceAddress);
@ -1403,11 +1383,25 @@ export function tornadoProgram() {
fetchDataOptions, fetchDataOptions,
cacheDirectory: EVENTS_DIR, cacheDirectory: EVENTS_DIR,
userDirectory: SAVED_DIR, userDirectory: SAVED_DIR,
nativeCurrency,
}; };
const depositsService = new NodeTornadoService({ const depositsService = new NodeTornadoService({
...TornadoServiceConstructor, ...TornadoServiceConstructor,
type: 'Deposit', type: 'Deposit',
merkleTreeService: new MerkleTreeService({
netId,
amount,
currency,
Tornado,
merkleWorkerPath,
}),
treeCache: new TreeCache({
netId,
amount,
currency,
userDirectory: SAVED_TREE_DIR,
}),
}); });
const withdrawalsService = new NodeTornadoService({ const withdrawalsService = new NodeTornadoService({
@ -1415,33 +1409,9 @@ export function tornadoProgram() {
type: 'Withdrawal', type: 'Withdrawal',
}); });
const merkleTreeService = new MerkleTreeService({ await depositsService.updateEvents();
netId,
amount,
currency,
Tornado,
merkleWorkerPath: MERKLE_WORKER_PATH,
});
const treeCache = new TreeCache({ await withdrawalsService.updateEvents();
netId,
amount,
currency,
userDirectory: SAVED_TREE_DIR,
});
const depositEvents = (await depositsService.updateEvents()).events as DepositsEvents[];
// If we have MERKLE_WORKER_PATH run worker at background otherwise resolve it here
const depositTreePromise = MERKLE_WORKER_PATH
? merkleTreeService.verifyTree(depositEvents)
: await merkleTreeService.verifyTree(depositEvents);
const [tree] = await Promise.all([depositTreePromise, withdrawalsService.updateEvents()]);
if (nativeCurrency === currency) {
await treeCache.createTree(depositEvents, tree);
}
} }
} }
} }
@ -1696,7 +1666,7 @@ export function tornadoProgram() {
[{ colSpan: 2, content: `Account key: ${accountKey}`, hAlign: 'center' }], [{ colSpan: 2, content: `Account key: ${accountKey}`, hAlign: 'center' }],
['blockNumber', 'note'].map((content) => ({ content: colors.red.bold(content) })), ['blockNumber', 'note'].map((content) => ({ content: colors.red.bold(content) })),
...noteAccount.decryptNotes(encryptedNoteEvents).map(({ blockNumber, address, noteHex }) => { ...noteAccount.decryptNotes(encryptedNoteEvents).map(({ blockNumber, address, noteHex }) => {
const { amount, currency } = getInstanceByAddress({ netId, address }) as { amount: string; currency: string }; const { amount, currency } = getInstanceByAddress(config, address) || {};
return [blockNumber, `tornado-${currency}-${amount}-${netId}-${noteHex}`]; return [blockNumber, `tornado-${currency}-${amount}-${netId}-${noteHex}`];
}), }),

@ -17,6 +17,7 @@ import {
BaseEchoService, BaseEchoService,
DEPOSIT, DEPOSIT,
CachedRelayers, CachedRelayers,
toFixedHex,
} from '@tornado/core'; } from '@tornado/core';
import type { import type {
BaseEvents, BaseEvents,
@ -26,17 +27,26 @@ import type {
RegistersEvents, RegistersEvents,
AllGovernanceEvents, AllGovernanceEvents,
EchoEvents, EchoEvents,
MerkleTreeService,
} from '@tornado/core'; } from '@tornado/core';
import { TreeCache } from './treeCache';
import { saveUserFile, loadSavedEvents, loadCachedEvents, saveLegacyFile, existsAsync } from './data'; import { saveUserFile, loadSavedEvents, loadCachedEvents, saveLegacyFile, existsAsync } from './data';
export type NodeTornadoServiceConstructor = BaseTornadoServiceConstructor & { export type NodeTornadoServiceConstructor = BaseTornadoServiceConstructor & {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: string; userDirectory: string;
nativeCurrency: string;
merkleTreeService?: MerkleTreeService;
treeCache?: TreeCache;
}; };
export class NodeTornadoService extends BaseTornadoService { export class NodeTornadoService extends BaseTornadoService {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: string; userDirectory: string;
nativeCurrency: string;
merkleTreeService?: MerkleTreeService;
treeCache?: TreeCache;
constructor({ constructor({
netId, netId,
@ -51,6 +61,9 @@ export class NodeTornadoService extends BaseTornadoService {
fetchDataOptions, fetchDataOptions,
cacheDirectory, cacheDirectory,
userDirectory, userDirectory,
nativeCurrency,
merkleTreeService,
treeCache,
}: NodeTornadoServiceConstructor) { }: NodeTornadoServiceConstructor) {
super({ super({
netId, netId,
@ -67,6 +80,10 @@ export class NodeTornadoService extends BaseTornadoService {
this.cacheDirectory = cacheDirectory; this.cacheDirectory = cacheDirectory;
this.userDirectory = userDirectory; this.userDirectory = userDirectory;
this.nativeCurrency = nativeCurrency;
this.merkleTreeService = merkleTreeService;
this.treeCache = treeCache;
} }
updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]) { updateEventProgress({ type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]) {
@ -190,6 +207,16 @@ export class NodeTornadoService extends BaseTornadoService {
console.log(eventTable.toString() + '\n'); console.log(eventTable.toString() + '\n');
if (this.userDirectory) { if (this.userDirectory) {
if (this.merkleTreeService) {
const tree = await this.merkleTreeService.verifyTree(events as DepositsEvents[]);
if (this.currency === this.nativeCurrency && this.treeCache) {
await this.treeCache.createTree(events as DepositsEvents[], tree);
console.log(`${this.getInstanceName()}: Updated tree cache with root ${toFixedHex(BigInt(tree.root))}\n`);
}
}
await saveUserFile({ await saveUserFile({
fileName: instanceName + '.json', fileName: instanceName + '.json',
userDirectory: this.userDirectory, userDirectory: this.userDirectory,
@ -226,13 +253,13 @@ export class NodeTornadoService extends BaseTornadoService {
} }
export type NodeEchoServiceConstructor = BaseEchoServiceConstructor & { export type NodeEchoServiceConstructor = BaseEchoServiceConstructor & {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: string; userDirectory: string;
}; };
export class NodeEchoService extends BaseEchoService { export class NodeEchoService extends BaseEchoService {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: string; userDirectory: string;
constructor({ constructor({
netId, netId,
@ -372,13 +399,13 @@ export class NodeEchoService extends BaseEchoService {
} }
export type NodeEncryptedNotesServiceConstructor = BaseEncryptedNotesServiceConstructor & { export type NodeEncryptedNotesServiceConstructor = BaseEncryptedNotesServiceConstructor & {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: string; userDirectory: string;
}; };
export class NodeEncryptedNotesService extends BaseEncryptedNotesService { export class NodeEncryptedNotesService extends BaseEncryptedNotesService {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: string; userDirectory: string;
constructor({ constructor({
netId, netId,
@ -530,13 +557,13 @@ export class NodeEncryptedNotesService extends BaseEncryptedNotesService {
} }
export type NodeGovernanceServiceConstructor = BaseGovernanceServiceConstructor & { export type NodeGovernanceServiceConstructor = BaseGovernanceServiceConstructor & {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: string; userDirectory: string;
}; };
export class NodeGovernanceService extends BaseGovernanceService { export class NodeGovernanceService extends BaseGovernanceService {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: string; userDirectory: string;
constructor({ constructor({
netId, netId,
@ -682,13 +709,13 @@ export class NodeGovernanceService extends BaseGovernanceService {
} }
export type NodeRegistryServiceConstructor = BaseRegistryServiceConstructor & { export type NodeRegistryServiceConstructor = BaseRegistryServiceConstructor & {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: string; userDirectory: string;
}; };
export class NodeRegistryService extends BaseRegistryService { export class NodeRegistryService extends BaseRegistryService {
cacheDirectory?: string; cacheDirectory: string;
userDirectory?: string; userDirectory: string;
constructor({ constructor({
netId, netId,

@ -781,9 +781,9 @@
"@openzeppelin/contracts-v3" "npm:@openzeppelin/contracts@3.2.0-rc.0" "@openzeppelin/contracts-v3" "npm:@openzeppelin/contracts@3.2.0-rc.0"
ethers "^6.4.0" ethers "^6.4.0"
"@tornado/core@git+https://git.tornado.ws/tornadocontrib/tornado-core.git#d0b032d7bef06de61872ba7ad07b769b9b1d9717": "@tornado/core@git+https://git.tornado.ws/tornadocontrib/tornado-core.git#f7fdf7db0a813ae2193f9864e212d68dc840c0d7":
version "1.0.13" version "1.0.14"
resolved "git+https://git.tornado.ws/tornadocontrib/tornado-core.git#d0b032d7bef06de61872ba7ad07b769b9b1d9717" resolved "git+https://git.tornado.ws/tornadocontrib/tornado-core.git#f7fdf7db0a813ae2193f9864e212d68dc840c0d7"
dependencies: dependencies:
"@metamask/eth-sig-util" "^7.0.3" "@metamask/eth-sig-util" "^7.0.3"
"@tornado/contracts" "^1.0.1" "@tornado/contracts" "^1.0.1"