Files
DLE/backend/routes/dleHistory.js

357 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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;