/** * Copyright (c) 2024-2025 Тарабанов Александр Викторович * All rights reserved. * * This software is proprietary and confidential. * Unauthorized copying, modification, or distribution is prohibited. * * For licensing inquiries: info@hb3-accelerator.com * Website: https://hb3-accelerator.com * GitHub: https://github.com/HB3-ACCELERATOR */ const express = require('express'); const router = express.Router(); const { ethers } = require('ethers'); const rpcProviderService = require('../services/rpcProviderService'); // Получить расширенную историю DLE router.post('/get-extended-history', async (req, res) => { try { const { dleAddress } = req.body; if (!dleAddress) { return res.status(400).json({ success: false, error: 'Адрес DLE обязателен' }); } console.log(`[DLE History] Получение расширенной истории для DLE: ${dleAddress}`); const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111); if (!rpcUrl) { return res.status(500).json({ success: false, error: 'RPC URL для Sepolia не найден' }); } const provider = new ethers.JsonRpcProvider(rpcUrl); const dleAbi = [ "function getDLEInfo() external view returns (tuple(string name, string symbol, string location, string coordinates, uint256 jurisdiction, uint256 oktmo, string[] okvedCodes, uint256 kpp, uint256 creationTimestamp, bool isActive))", "function getGovernanceParams() external view returns (uint256 quorumPct, uint256 chainId, uint256 supportedCount)", "function getCurrentChainId() external view returns (uint256)", "function listSupportedChains() external view returns (uint256[] memory)", "function getProposalsCount() external view returns (uint256)" ]; const dle = new ethers.Contract(dleAddress, dleAbi, provider); // Получаем текущие данные для сравнения const dleInfo = await dle.getDLEInfo(); const governanceParams = await dle.getGovernanceParams(); const currentChainId = await dle.getCurrentChainId(); const supportedChains = await dle.listSupportedChains(); const proposalsCount = await dle.getProposalsCount(); const history = []; // 1. Событие создания DLE history.push({ id: 1, type: 'dle_created', title: 'DLE создан', description: `Создан DLE "${dleInfo.name}" (${dleInfo.symbol})`, timestamp: Number(dleInfo.creationTimestamp) * 1000, blockNumber: 0, transactionHash: '0x0000000000000000000000000000000000000000000000000000000000000000', details: { name: dleInfo.name, symbol: dleInfo.symbol, location: dleInfo.location, jurisdiction: Number(dleInfo.jurisdiction), supportedChains: supportedChains.map(chain => Number(chain)) } }); // 2. История изменений настроек (кворум, цепочка) const currentBlock = await provider.getBlockNumber(); const fromBlock = Math.max(0, currentBlock - 10000); try { // События изменения кворума const quorumEvents = await dle.queryFilter('QuorumPercentageUpdated', fromBlock, currentBlock); for (let i = 0; i < quorumEvents.length; i++) { const event = quorumEvents[i]; history.push({ id: history.length + 1, type: 'quorum_updated', title: 'Изменен кворум', description: `Кворум изменен с ${Number(event.args.oldQuorumPercentage)}% на ${Number(event.args.newQuorumPercentage)}%`, timestamp: event.blockNumber * 1000, blockNumber: event.blockNumber, transactionHash: event.transactionHash, details: { oldQuorum: Number(event.args.oldQuorumPercentage), newQuorum: Number(event.args.newQuorumPercentage) } }); } // События изменения текущей цепочки const chainEvents = await dle.queryFilter('CurrentChainIdUpdated', fromBlock, currentBlock); for (let i = 0; i < chainEvents.length; i++) { const event = chainEvents[i]; history.push({ id: history.length + 1, type: 'chain_updated', title: 'Изменена текущая цепочка', description: `Текущая цепочка изменена с ${Number(event.args.oldChainId)} на ${Number(event.args.newChainId)}`, timestamp: event.blockNumber * 1000, blockNumber: event.blockNumber, transactionHash: event.transactionHash, details: { oldChainId: Number(event.args.oldChainId), newChainId: Number(event.args.newChainId) } }); } // События обновления информации DLE const infoEvents = await dle.queryFilter('DLEInfoUpdated', fromBlock, currentBlock); for (let i = 0; i < infoEvents.length; i++) { const event = infoEvents[i]; history.push({ id: history.length + 1, type: 'dle_info_updated', title: 'Обновлена информация DLE', description: `Обновлена информация: ${event.args.name} (${event.args.symbol})`, timestamp: event.blockNumber * 1000, blockNumber: event.blockNumber, transactionHash: event.transactionHash, details: { name: event.args.name, symbol: event.args.symbol, location: event.args.location, jurisdiction: Number(event.args.jurisdiction) } }); } // 3. История модулей const moduleAddedEvents = await dle.queryFilter('ModuleAdded', fromBlock, currentBlock); for (let i = 0; i < moduleAddedEvents.length; i++) { const event = moduleAddedEvents[i]; const moduleName = getModuleName(event.args.moduleId); history.push({ id: history.length + 1, type: 'module_added', title: 'Модуль добавлен', description: `Добавлен модуль "${moduleName}"`, timestamp: event.blockNumber * 1000, blockNumber: event.blockNumber, transactionHash: event.transactionHash, details: { moduleId: event.args.moduleId, moduleName: moduleName, moduleAddress: event.args.moduleAddress } }); } const moduleRemovedEvents = await dle.queryFilter('ModuleRemoved', fromBlock, currentBlock); for (let i = 0; i < moduleRemovedEvents.length; i++) { const event = moduleRemovedEvents[i]; const moduleName = getModuleName(event.args.moduleId); history.push({ id: history.length + 1, type: 'module_removed', title: 'Модуль удален', description: `Удален модуль "${moduleName}"`, timestamp: event.blockNumber * 1000, blockNumber: event.blockNumber, transactionHash: event.transactionHash, details: { moduleId: event.args.moduleId, moduleName: moduleName } }); } // 4. Мульти-чейн история const chainAddedEvents = await dle.queryFilter('ChainAdded', fromBlock, currentBlock); for (let i = 0; i < chainAddedEvents.length; i++) { const event = chainAddedEvents[i]; const chainName = getChainName(Number(event.args.chainId)); history.push({ id: history.length + 1, type: 'chain_added', title: 'Сеть добавлена', description: `Добавлена сеть "${chainName}" (ID: ${Number(event.args.chainId)})`, timestamp: event.blockNumber * 1000, blockNumber: event.blockNumber, transactionHash: event.transactionHash, details: { chainId: Number(event.args.chainId), chainName: chainName } }); } const chainRemovedEvents = await dle.queryFilter('ChainRemoved', fromBlock, currentBlock); for (let i = 0; i < chainRemovedEvents.length; i++) { const event = chainRemovedEvents[i]; const chainName = getChainName(Number(event.args.chainId)); history.push({ id: history.length + 1, type: 'chain_removed', title: 'Сеть удалена', description: `Удалена сеть "${chainName}" (ID: ${Number(event.args.chainId)})`, timestamp: event.blockNumber * 1000, blockNumber: event.blockNumber, transactionHash: event.transactionHash, details: { chainId: Number(event.args.chainId), chainName: chainName } }); } const executionApprovedEvents = await dle.queryFilter('ProposalExecutionApprovedInChain', fromBlock, currentBlock); for (let i = 0; i < executionApprovedEvents.length; i++) { const event = executionApprovedEvents[i]; const chainName = getChainName(Number(event.args.chainId)); history.push({ id: history.length + 1, type: 'proposal_execution_approved', title: 'Исполнение предложения одобрено', description: `Исполнение предложения #${Number(event.args.proposalId)} одобрено в сети "${chainName}"`, timestamp: event.blockNumber * 1000, blockNumber: event.blockNumber, transactionHash: event.transactionHash, details: { proposalId: Number(event.args.proposalId), chainId: Number(event.args.chainId), chainName: chainName } }); } // 5. События предложений (базовые) const proposalEvents = await dle.queryFilter('ProposalCreated', fromBlock, currentBlock); for (let i = 0; i < proposalEvents.length; i++) { const event = proposalEvents[i]; history.push({ id: history.length + 1, type: 'proposal_created', title: `Предложение #${Number(event.args.proposalId)} создано`, description: event.args.description, timestamp: event.blockNumber * 1000, blockNumber: event.blockNumber, transactionHash: event.transactionHash, details: { proposalId: Number(event.args.proposalId), initiator: event.args.initiator, description: event.args.description } }); } const proposalExecutedEvents = await dle.queryFilter('ProposalExecuted', fromBlock, currentBlock); for (let i = 0; i < proposalExecutedEvents.length; i++) { const event = proposalExecutedEvents[i]; history.push({ id: history.length + 1, type: 'proposal_executed', title: `Предложение #${Number(event.args.proposalId)} исполнено`, description: `Предложение успешно исполнено`, timestamp: event.blockNumber * 1000, blockNumber: event.blockNumber, transactionHash: event.transactionHash, details: { proposalId: Number(event.args.proposalId), operation: event.args.operation } }); } const proposalCancelledEvents = await dle.queryFilter('ProposalCancelled', fromBlock, currentBlock); for (let i = 0; i < proposalCancelledEvents.length; i++) { const event = proposalCancelledEvents[i]; history.push({ id: history.length + 1, type: 'proposal_cancelled', title: `Предложение #${Number(event.args.proposalId)} отменено`, description: `Причина: ${event.args.reason}`, timestamp: event.blockNumber * 1000, blockNumber: event.blockNumber, transactionHash: event.transactionHash, details: { proposalId: Number(event.args.proposalId), reason: event.args.reason } }); } } catch (error) { console.log(`[DLE History] Ошибка при получении событий:`, error.message); } // Сортируем по времени (новые сверху) history.sort((a, b) => b.timestamp - a.timestamp); console.log(`[DLE History] Расширенная история получена:`, history.length, 'событий'); res.json({ success: true, data: { history: history, totalEvents: history.length, dleInfo: { name: dleInfo.name, symbol: dleInfo.symbol, creationTimestamp: Number(dleInfo.creationTimestamp), proposalsCount: Number(proposalsCount), currentChainId: Number(currentChainId), supportedChains: supportedChains.map(chain => Number(chain)) } } }); } catch (error) { console.error('[DLE History] Ошибка при получении расширенной истории:', error); res.status(500).json({ success: false, error: 'Ошибка при получении расширенной истории: ' + error.message }); } }); // Вспомогательные функции function getModuleName(moduleId) { const moduleNames = { '0x7472656173757279000000000000000000000000000000000000000000000000': 'Treasury', '0x6d756c7469736967000000000000000000000000000000000000000000000000': 'Multisig', '0x646561637469766174696f6e0000000000000000000000000000000000000000': 'Deactivation', '0x616e616c79746963730000000000000000000000000000000000000000000000': 'Analytics', '0x6e6f74696669636174696f6e7300000000000000000000000000000000000000': 'Notifications' }; return moduleNames[moduleId] || `Module ${moduleId}`; } function getChainName(chainId) { const chainNames = { 1: 'Ethereum Mainnet', 11155111: 'Sepolia Testnet', 137: 'Polygon', 56: 'BSC', 42161: 'Arbitrum One', 17000: 'Holesky Testnet' }; return chainNames[chainId] || `Chain ID: ${chainId}`; } module.exports = router;