"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.NodeRevenueService = exports.NodeRegistryService = exports.NodeGovernanceService = exports.NodeEncryptedNotesService = exports.NodeEchoService = exports.NodeMultiTornadoService = exports.NodeTornadoService = exports.NodeTransactionsService = exports.NodeBlocksService = exports.NodeEventsService = void 0; const path_1 = __importDefault(require("path")); const promises_1 = require("fs/promises"); const core_1 = require("@tornado/core"); const contracts_1 = require("@tornado/contracts"); const data_1 = require("./data"); class NodeEventsService extends core_1.BatchEventsService { netId; logger; getInstanceName; constructor(serviceConstructor) { super(serviceConstructor); this.netId = serviceConstructor.netId; this.logger = serviceConstructor.logger; this.getInstanceName = serviceConstructor.getInstanceName; } } exports.NodeEventsService = NodeEventsService; class NodeBlocksService extends core_1.BatchBlockService { netId; logger; getInstanceName; constructor(serviceConstructor) { super(serviceConstructor); this.netId = serviceConstructor.netId; this.logger = serviceConstructor.logger; this.getInstanceName = serviceConstructor.getInstanceName; } } exports.NodeBlocksService = NodeBlocksService; class NodeTransactionsService extends core_1.BatchTransactionService { netId; logger; getInstanceName; constructor(serviceConstructor) { super(serviceConstructor); this.netId = serviceConstructor.netId; this.logger = serviceConstructor.logger; this.getInstanceName = serviceConstructor.getInstanceName; } } exports.NodeTransactionsService = NodeTransactionsService; class NodeTornadoService extends core_1.BaseTornadoService { cacheDirectory; userDirectory; nativeCurrency; logger; treeCache; constructor(serviceConstructor) { super(serviceConstructor); const { netId, provider, Tornado, type, amount, currency, cacheDirectory, userDirectory, nativeCurrency, logger, treeCache, } = serviceConstructor; this.cacheDirectory = cacheDirectory; this.userDirectory = userDirectory; this.nativeCurrency = nativeCurrency; this.logger = logger; this.batchEventsService = new NodeEventsService({ netId, provider, contract: Tornado, onProgress: this.updateEventProgress, logger, getInstanceName: () => `${type.toLowerCase()}s_${netId}_${currency}_${amount}`, }); this.batchTransactionService = new NodeTransactionsService({ netId, provider, onProgress: this.updateTransactionProgress, logger, getInstanceName: () => `${type.toLowerCase()}s_${netId}_${currency}_${amount}`, }); this.batchBlockService = new NodeBlocksService({ netId, provider, onProgress: this.updateBlockProgress, logger, getInstanceName: () => `${type.toLowerCase()}s_${netId}_${currency}_${amount}`, }); this.treeCache = treeCache; } updateEventProgress({ fromBlock, toBlock, count }) { if (toBlock) { this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); } } updateTransactionProgress({ currentIndex, totalIndex }) { if (totalIndex) { this.logger.debug(`${this.getInstanceName()}: Fetched ${currentIndex} deposit txs of ${totalIndex}`); } } updateBlockProgress({ currentIndex, totalIndex }) { if (totalIndex) { this.logger.debug(`${this.getInstanceName()}: Fetched ${currentIndex} withdrawal blocks of ${totalIndex}`); } } async getEventsFromDB() { return await (0, data_1.loadSavedEvents)({ name: this.getInstanceName(), userDirectory: this.userDirectory, }); } async getEventsFromCache() { return await (0, data_1.loadCachedEvents)({ name: this.getInstanceName(), cacheDirectory: this.cacheDirectory, deployedBlock: this.deployedBlock, }); } async validateEvents({ events, newEvents, lastBlock, }) { const tree = await super.validateEvents({ events, newEvents, lastBlock, }); if (tree && this.currency === this.nativeCurrency && this.treeCache) { const merkleTree = tree; await this.treeCache.createTree({ netId: this.netId, amount: this.amount, currency: this.currency, events: events, tree: tree, }); console.log(`${this.getInstanceName()}: Updated tree cache with root ${(0, core_1.toFixedHex)(BigInt(merkleTree.root))}\n`); } return tree; } async saveEvents({ events, lastBlock }) { await (0, data_1.saveUserFile)({ fileName: this.getInstanceName() + '.json', userDirectory: this.userDirectory, dataString: JSON.stringify(events, null, 2) + '\n', lastBlock, }); } async updateEvents() { const { events, lastBlock, validateResult } = await super.updateEvents(); await (0, data_1.saveLastBlock)({ fileName: this.getInstanceName(), userDirectory: this.userDirectory, lastBlock, }); return { events, lastBlock, validateResult, }; } } exports.NodeTornadoService = NodeTornadoService; class NodeMultiTornadoService extends core_1.BaseMultiTornadoService { cacheDirectory; userDirectory; nativeCurrency; logger; treeCache; constructor(serviceConstructor) { super(serviceConstructor); const { netId, provider, cacheDirectory, userDirectory, nativeCurrency, logger, treeCache } = serviceConstructor; this.cacheDirectory = cacheDirectory; this.userDirectory = userDirectory; this.nativeCurrency = nativeCurrency; this.logger = logger; this.batchEventsService = new NodeEventsService({ netId, provider, contract: this.contract, address: Object.keys(this.instances), onProgress: this.updateEventProgress, logger, getInstanceName: this.getInstanceName, }); this.batchTransactionService = new NodeTransactionsService({ netId, provider, onProgress: this.updateTransactionProgress, logger, getInstanceName: this.getInstanceName, }); this.batchBlockService = new NodeBlocksService({ netId, provider, onProgress: this.updateBlockProgress, logger, getInstanceName: this.getInstanceName, }); this.treeCache = treeCache; } updateEventProgress({ fromBlock, toBlock, count }) { if (toBlock) { this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); } } updateTransactionProgress({ currentIndex, totalIndex }) { if (totalIndex) { this.logger.debug(`${this.getInstanceName()}: Fetched ${currentIndex} deposit txs of ${totalIndex}`); } } updateBlockProgress({ currentIndex, totalIndex }) { if (totalIndex) { this.logger.debug(`${this.getInstanceName()}: Fetched ${currentIndex} withdrawal blocks of ${totalIndex}`); } } async getEventsFromDB() { return await (0, data_1.loadSavedEvents)({ name: this.getInstanceName(), userDirectory: this.userDirectory, }); } async getEventsFromCache() { return await (0, data_1.loadCachedEvents)({ name: this.getInstanceName(), cacheDirectory: this.cacheDirectory, deployedBlock: this.deployedBlock, }); } async validateEvents({ events, newEvents, lastBlock, }) { const tree = await super.validateEvents({ events, newEvents, lastBlock, }); if (this.merkleTreeService && this.treeCache) { const instancesWithNewEvents = [ ...new Set(newEvents.filter(({ event }) => event === 'Deposit').map(({ instanceAddress }) => instanceAddress)), ]; for (const instance of instancesWithNewEvents) { const { amount, currency } = this.instances[instance]; // Only create cached tree for native currencies if (currency !== this.nativeCurrency) { continue; } const depositEvents = events.filter(({ instanceAddress, event }) => instanceAddress === instance && event === 'Deposit'); // Create tree cache with existing tree if (tree && this.merkleTreeService.Tornado.target === instance) { await this.treeCache.createTree({ netId: this.netId, amount, currency, events: depositEvents, tree: tree, }); // Create new tree cache } else { const merkleTreeService = new core_1.MerkleTreeService({ netId: this.netId, amount, currency, Tornado: contracts_1.Tornado__factory.connect(instance, this.provider), merkleWorkerPath: this.merkleTreeService.merkleWorkerPath, }); const tree = await merkleTreeService.verifyTree(depositEvents); await this.treeCache.createTree({ netId: this.netId, amount, currency, events: depositEvents, tree, }); } } } return tree; } async saveEvents({ events, newEvents, lastBlock, }) { const instancesWithNewEvents = [...new Set(newEvents.map(({ instanceAddress }) => instanceAddress))]; for (const instance of instancesWithNewEvents) { const { currency, amount } = this.instances[instance]; const { depositEvents, withdrawalEvents } = events.reduce((acc, curr) => { if (curr.instanceAddress === instance) { if (curr.event === 'Deposit') { acc.depositEvents.push({ ...curr, event: undefined, instanceAddress: undefined, }); } else if (curr.event === 'Withdrawal') { acc.withdrawalEvents.push({ ...curr, event: undefined, instanceAddress: undefined, relayerAddress: undefined, }); } } return acc; }, { depositEvents: [], withdrawalEvents: [], }); await (0, promises_1.writeFile)(path_1.default.join(this.userDirectory, `recent_deposits_${this.netId}_${currency}_${amount}.json`), JSON.stringify(depositEvents.slice(depositEvents.length - 10).reverse(), null, 2) + '\n'); await (0, data_1.saveUserFile)({ fileName: `deposits_${this.netId}_${currency}_${amount}.json`, userDirectory: this.userDirectory, dataString: JSON.stringify(depositEvents, null, 2) + '\n', lastBlock, }); await (0, data_1.saveUserFile)({ fileName: `withdrawals_${this.netId}_${currency}_${amount}.json`, userDirectory: this.userDirectory, dataString: JSON.stringify(withdrawalEvents, null, 2) + '\n', lastBlock, }); console.log(`\nSaved ${this.netId}_${currency}_${amount}.json event: ` + `${depositEvents.length} deposits ${withdrawalEvents.length} withdrawals\n`); } await (0, data_1.saveUserFile)({ fileName: this.getInstanceName() + '.json', userDirectory: this.userDirectory, dataString: JSON.stringify(events, null, 2) + '\n', lastBlock, }); } async updateEvents() { const { events, lastBlock, validateResult } = await super.updateEvents(); await (0, data_1.saveLastBlock)({ fileName: this.getInstanceName(), userDirectory: this.userDirectory, lastBlock, }); return { events, lastBlock, validateResult, }; } } exports.NodeMultiTornadoService = NodeMultiTornadoService; class NodeEchoService extends core_1.BaseEchoService { cacheDirectory; userDirectory; logger; constructor(serviceConstructor) { super(serviceConstructor); const { netId, provider, Echoer, cacheDirectory, userDirectory, logger } = serviceConstructor; this.cacheDirectory = cacheDirectory; this.userDirectory = userDirectory; this.logger = logger; this.batchEventsService = new NodeEventsService({ netId, provider, contract: Echoer, onProgress: this.updateEventProgress, logger, getInstanceName: this.getInstanceName, }); } updateEventProgress({ fromBlock, toBlock, count }) { if (toBlock) { this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); } } async getEventsFromDB() { return await (0, data_1.loadSavedEvents)({ name: this.getInstanceName(), userDirectory: this.userDirectory, }); } async getEventsFromCache() { return await (0, data_1.loadCachedEvents)({ name: this.getInstanceName(), cacheDirectory: this.cacheDirectory, deployedBlock: this.deployedBlock, }); } async saveEvents({ events, lastBlock }) { const instanceName = this.getInstanceName(); await (0, data_1.saveUserFile)({ fileName: instanceName + '.json', userDirectory: this.userDirectory, dataString: JSON.stringify(events, null, 2) + '\n', lastBlock, }); } async updateEvents() { const { events, lastBlock, validateResult } = await super.updateEvents(); await (0, data_1.saveLastBlock)({ fileName: this.getInstanceName(), userDirectory: this.userDirectory, lastBlock, }); return { events, lastBlock, validateResult, }; } } exports.NodeEchoService = NodeEchoService; class NodeEncryptedNotesService extends core_1.BaseEncryptedNotesService { cacheDirectory; userDirectory; logger; constructor(serviceConstructor) { super(serviceConstructor); const { netId, provider, Router, cacheDirectory, userDirectory, logger } = serviceConstructor; this.cacheDirectory = cacheDirectory; this.userDirectory = userDirectory; this.logger = logger; this.batchEventsService = new NodeEventsService({ netId, provider, contract: Router, onProgress: this.updateEventProgress, logger, getInstanceName: this.getInstanceName, }); } updateEventProgress({ fromBlock, toBlock, count }) { if (toBlock) { this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); } } async getEventsFromDB() { return await (0, data_1.loadSavedEvents)({ name: this.getInstanceName(), userDirectory: this.userDirectory, }); } async getEventsFromCache() { return await (0, data_1.loadCachedEvents)({ name: this.getInstanceName(), cacheDirectory: this.cacheDirectory, deployedBlock: this.deployedBlock, }); } async saveEvents({ events, lastBlock }) { const instanceName = this.getInstanceName(); await (0, data_1.saveUserFile)({ fileName: instanceName + '.json', userDirectory: this.userDirectory, dataString: JSON.stringify(events, null, 2) + '\n', lastBlock, }); } async updateEvents() { const { events, lastBlock, validateResult } = await super.updateEvents(); await (0, data_1.saveLastBlock)({ fileName: this.getInstanceName(), userDirectory: this.userDirectory, lastBlock, }); return { events, lastBlock, validateResult, }; } } exports.NodeEncryptedNotesService = NodeEncryptedNotesService; class NodeGovernanceService extends core_1.BaseGovernanceService { cacheDirectory; userDirectory; logger; constructor(serviceConstructor) { super(serviceConstructor); const { netId, provider, Governance, cacheDirectory, userDirectory, logger } = serviceConstructor; this.cacheDirectory = cacheDirectory; this.userDirectory = userDirectory; this.logger = logger; this.batchEventsService = new NodeEventsService({ netId, provider, contract: Governance, onProgress: this.updateEventProgress, logger, getInstanceName: this.getInstanceName, }); this.batchTransactionService = new NodeTransactionsService({ netId, provider, onProgress: this.updateTransactionProgress, logger, getInstanceName: this.getInstanceName, }); } updateEventProgress({ fromBlock, toBlock, count }) { if (toBlock) { this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); } } updateTransactionProgress({ currentIndex, totalIndex }) { if (totalIndex) { this.logger.debug(`${this.getInstanceName()}: Fetched ${currentIndex} governance txs of ${totalIndex}`); } } async getEventsFromDB() { return await (0, data_1.loadSavedEvents)({ name: this.getInstanceName(), userDirectory: this.userDirectory, }); } async getEventsFromCache() { return await (0, data_1.loadCachedEvents)({ name: this.getInstanceName(), cacheDirectory: this.cacheDirectory, deployedBlock: this.deployedBlock, }); } async saveEvents({ events, lastBlock }) { const instanceName = this.getInstanceName(); await (0, data_1.saveUserFile)({ fileName: instanceName + '.json', userDirectory: this.userDirectory, dataString: JSON.stringify(events, null, 2) + '\n', lastBlock, }); } async updateEvents() { const { events, lastBlock, validateResult } = await super.updateEvents(); await (0, data_1.saveLastBlock)({ fileName: this.getInstanceName(), userDirectory: this.userDirectory, lastBlock, }); return { events, lastBlock, validateResult, }; } } exports.NodeGovernanceService = NodeGovernanceService; class NodeRegistryService extends core_1.BaseRegistryService { cacheDirectory; userDirectory; logger; constructor(serviceConstructor) { super(serviceConstructor); const { netId, provider, RelayerRegistry, cacheDirectory, userDirectory, logger } = serviceConstructor; this.cacheDirectory = cacheDirectory; this.userDirectory = userDirectory; this.logger = logger; this.batchEventsService = new NodeEventsService({ netId, provider, contract: RelayerRegistry, onProgress: this.updateEventProgress, logger, getInstanceName: this.getInstanceName, }); } updateEventProgress({ fromBlock, toBlock, count }) { if (toBlock) { this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); } } async getEventsFromDB() { return await (0, data_1.loadSavedEvents)({ name: this.getInstanceName(), userDirectory: this.userDirectory, }); } async getEventsFromCache() { return await (0, data_1.loadCachedEvents)({ name: this.getInstanceName(), cacheDirectory: this.cacheDirectory, deployedBlock: this.deployedBlock, }); } async saveEvents({ events, lastBlock }) { const instanceName = this.getInstanceName(); await (0, data_1.saveUserFile)({ fileName: instanceName + '.json', userDirectory: this.userDirectory, dataString: JSON.stringify(events, null, 2) + '\n', lastBlock, }); } async updateEvents() { const { events, lastBlock, validateResult } = await super.updateEvents(); await (0, data_1.saveLastBlock)({ fileName: this.getInstanceName(), userDirectory: this.userDirectory, lastBlock, }); return { events, lastBlock, validateResult, }; } async getRelayersFromDB() { const filePath = path_1.default.join(this.userDirectory || '', 'relayers.json'); if (!this.userDirectory || !(await (0, data_1.existsAsync)(filePath))) { return { lastBlock: 0, timestamp: 0, relayers: [], }; } try { const { lastBlock, timestamp, relayers } = JSON.parse(await (0, promises_1.readFile)(filePath, { encoding: 'utf8' })); return { lastBlock, timestamp, relayers, }; } catch (err) { console.log('Method getRelayersFromDB has error'); console.log(err); return { lastBlock: 0, timestamp: 0, relayers: [], }; } } async getRelayersFromCache() { const filePath = path_1.default.join(this.cacheDirectory || '', 'relayers.json'); if (!this.cacheDirectory || !(await (0, data_1.existsAsync)(filePath))) { return { lastBlock: 0, timestamp: 0, relayers: [], fromCache: true, }; } try { const { lastBlock, timestamp, relayers } = JSON.parse(await (0, promises_1.readFile)(filePath, { encoding: 'utf8' })); return { lastBlock, timestamp, relayers, fromCache: true, }; } catch (err) { console.log('Method getRelayersFromDB has error'); console.log(err); return { lastBlock: 0, timestamp: 0, relayers: [], fromCache: true, }; } } async saveRelayers({ lastBlock, timestamp, relayers }) { await (0, data_1.saveUserFile)({ fileName: 'relayers.json', userDirectory: this.userDirectory, dataString: JSON.stringify({ lastBlock, timestamp, relayers }, null, 2) + '\n', }); } } exports.NodeRegistryService = NodeRegistryService; class NodeRevenueService extends core_1.BaseRevenueService { cacheDirectory; userDirectory; logger; constructor(serviceConstructor) { super(serviceConstructor); const { netId, provider, RelayerRegistry, cacheDirectory, userDirectory, logger } = serviceConstructor; this.cacheDirectory = cacheDirectory; this.userDirectory = userDirectory; this.logger = logger; this.batchEventsService = new NodeEventsService({ netId, provider, contract: RelayerRegistry, onProgress: this.updateEventProgress, logger, getInstanceName: this.getInstanceName, }); this.batchTransactionService = new NodeTransactionsService({ netId, provider, onProgress: this.updateTransactionProgress, logger, getInstanceName: this.getInstanceName, }); this.batchBlockService = new NodeBlocksService({ netId, provider, onProgress: this.updateBlockProgress, logger, getInstanceName: this.getInstanceName, }); } updateEventProgress({ fromBlock, toBlock, count }) { if (toBlock) { this.logger.debug(`${this.getInstanceName()}: Fetched ${count} events from ${fromBlock} to ${toBlock}`); } } updateTransactionProgress({ currentIndex, totalIndex }) { if (totalIndex) { this.logger.debug(`${this.getInstanceName()}: Fetched ${currentIndex} txs of ${totalIndex}`); } } updateBlockProgress({ currentIndex, totalIndex }) { if (totalIndex) { this.logger.debug(`${this.getInstanceName()}: Fetched ${currentIndex} blocks of ${totalIndex}`); } } async getEventsFromDB() { return await (0, data_1.loadSavedEvents)({ name: this.getInstanceName(), userDirectory: this.userDirectory, }); } async getEventsFromCache() { return await (0, data_1.loadCachedEvents)({ name: this.getInstanceName(), cacheDirectory: this.cacheDirectory, deployedBlock: this.deployedBlock, }); } async saveEvents({ events, lastBlock }) { const instanceName = this.getInstanceName(); await (0, data_1.saveUserFile)({ fileName: instanceName + '.json', userDirectory: this.userDirectory, dataString: JSON.stringify(events, null, 2) + '\n', lastBlock, }); } async updateEvents() { const { events, lastBlock, validateResult } = await super.updateEvents(); await (0, data_1.saveLastBlock)({ fileName: this.getInstanceName(), userDirectory: this.userDirectory, lastBlock, }); return { events, lastBlock, validateResult, }; } } exports.NodeRevenueService = NodeRevenueService;