ваше сообщение коммита
This commit is contained in:
356
backend/routes/dleHistory.js
Normal file
356
backend/routes/dleHistory.js
Normal file
@@ -0,0 +1,356 @@
|
||||
/**
|
||||
* 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;
|
||||
Reference in New Issue
Block a user