diff --git a/backend/routes/dleModules.js b/backend/routes/dleModules.js index 01d84c5..27abf61 100644 --- a/backend/routes/dleModules.js +++ b/backend/routes/dleModules.js @@ -160,62 +160,204 @@ router.post('/get-all-modules', async (req, res) => { }); } - console.log(`[DLE Modules] Получение всех модулей для DLE: ${dleAddress}`); + console.log(`[DLE Modules] Получение всех модулей для 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); + // Сначала пытаемся получить модули из файлов деплоя + console.log(`[DLE Modules] Вызываем getDeployedModulesInfo...`); + const modulesInfo = await getDeployedModulesInfo(dleAddress); + console.log(`[DLE Modules] Результат getDeployedModulesInfo:`, modulesInfo); - const dleAbi = [ - "function isModuleActive(bytes32 _moduleId) external view returns (bool)", - "function getModuleAddress(bytes32 _moduleId) external view returns (address)" - ]; - - const dle = new ethers.Contract(dleAddress, dleAbi, provider); - - // Список известных модулей для проверки - const knownModules = [ - "0x7472656173757279000000000000000000000000000000000000000000000000", // "treasury" - "0x6d756c7469736967000000000000000000000000000000000000000000000000", // "multisig" - "0x646561637469766174696f6e0000000000000000000000000000000000000000", // "deactivation" - "0x616e616c79746963730000000000000000000000000000000000000000000000", // "analytics" - "0x6e6f74696669636174696f6e7300000000000000000000000000000000000000" // "notifications" - ]; - - const modules = []; - - // Проверяем активность известных модулей - for (const moduleId of knownModules) { - try { - const isActive = await dle.isModuleActive(moduleId); - if (isActive) { - const address = await dle.getModuleAddress(moduleId); - modules.push({ - id: moduleId, - address: address, - isActive: isActive + if (modulesInfo.modules && modulesInfo.modules.length > 0) { + console.log(`[DLE Modules] Модули найдены в файлах, количество: ${modulesInfo.modules.length}`); + + // Преобразуем данные в нужный формат для frontend + // Группируем модули по типам, а не по сетям + const moduleGroups = { + treasury: { + moduleId: "0x747265617375727900000000000000000000000000000000000000000000000000", + moduleName: "TREASURY", + moduleDescription: "Казначейство DLE - управление финансами, депозиты, выводы, дивиденды", + addresses: [], + isActive: true, + deployedAt: modulesInfo.deployTimestamp + }, + timelock: { + moduleId: "0x74696d656c6f636b000000000000000000000000000000000000000000000000", + moduleName: "TIMELOCK", + moduleDescription: "Модуль задержек исполнения - безопасность критических операций через таймлоки", + addresses: [], + isActive: true, + deployedAt: modulesInfo.deployTimestamp + }, + reader: { + moduleId: "0x726561646572000000000000000000000000000000000000000000000000000000", + moduleName: "READER", + moduleDescription: "Модуль чтения данных DLE - получение информации о контракте", + addresses: [], + isActive: true, + deployedAt: modulesInfo.deployTimestamp + } + }; + + // Собираем адреса для каждого типа модуля из всех сетей + // Определяем реальные chainId для каждого адреса + for (let networkIndex = 0; networkIndex < modulesInfo.modules.length; networkIndex++) { + const networkModules = modulesInfo.modules[networkIndex]; + + console.log(`[DLE Modules] Обрабатываем сеть ${networkIndex + 1}:`, networkModules); + + // Получаем информацию о сети из файла деплоя + let chainId = null; + let networkName = `Сеть ${networkIndex + 1}`; + + // Если в файле есть информация о сетях, используем её + if (modulesInfo.networks && modulesInfo.networks[networkIndex]) { + chainId = modulesInfo.networks[networkIndex].chainId; + networkName = modulesInfo.networks[networkIndex].networkName || `Сеть ${networkIndex + 1}`; + } + + if (networkModules.treasuryModule) { + moduleGroups.treasury.addresses.push({ + address: networkModules.treasuryModule, + networkName: networkName, + networkIndex: networkIndex, + chainId: chainId, + verificationStatus: modulesInfo.verification?.[networkIndex]?.treasuryModule || 'pending' }); } + + if (networkModules.timelockModule) { + moduleGroups.timelock.addresses.push({ + address: networkModules.timelockModule, + networkName: networkName, + networkIndex: networkIndex, + chainId: chainId, + verificationStatus: modulesInfo.verification?.[networkIndex]?.timelockModule || 'pending' + }); + } + + if (networkModules.dleReader) { + moduleGroups.reader.addresses.push({ + address: networkModules.dleReader, + networkName: networkName, + networkIndex: networkIndex, + chainId: chainId, + verificationStatus: modulesInfo.verification?.[networkIndex]?.dleReader || 'pending' + }); + } + } + + // Преобразуем в массив модулей + const formattedModules = Object.values(moduleGroups).filter(module => module.addresses.length > 0); + + console.log(`[DLE Modules] Сгруппированные модули:`, formattedModules); + console.log(`[DLE Modules] Найдено типов модулей: ${formattedModules.length}`); + + res.json({ + success: true, + data: { + modules: formattedModules, + modulesInitialized: true, + totalModules: formattedModules.length, + activeModules: formattedModules.length + } + }); + } else { + console.log(`[DLE Modules] Файлы модулей не найдены или пусты, проверяем блокчейн для 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 isModuleActive(bytes32 _moduleId) external view returns (bool)", + "function getModuleAddress(bytes32 _moduleId) external view returns (address)", + "function modulesInitialized() external view returns (bool)" + ]; + + const dle = new ethers.Contract(dleAddress, dleAbi, provider); + + // Проверяем инициализацию модулей + let modulesInitialized = false; + try { + modulesInitialized = await dle.modulesInitialized(); } catch (error) { - console.log(`[DLE Modules] Ошибка при проверке модуля ${moduleId}:`, error.message); + console.log(`[DLE Modules] Ошибка при проверке инициализации модулей:`, error.message); } + + if (!modulesInitialized) { + console.log(`[DLE Modules] Модули для DLE ${dleAddress} не инициализированы`); + return res.json({ + success: true, + data: { + modules: [], + modulesInitialized: false, + totalModules: 0, + activeModules: 0 + } + }); + } + + // Список стандартных модулей DLE + const standardModuleIds = [ + "0x7472656173757279000000000000000000000000000000000000000000000000", // "treasury" + "0x74696d656c6f636b000000000000000000000000000000000000000000000000", // "timelock" + "0x6d696e7400000000000000000000000000000000000000000000000000000000", // "mint" + "0x6275726e00000000000000000000000000000000000000000000000000000000", // "burn" + "0x6f7261636c650000000000000000000000000000000000000000000000000000", // "oracle" + "0x696e6865726974616e6365000000000000000000000000000000000000000000", // "inheritance" + "0x636f6d6d756e69636174696f6e00000000000000000000000000000000000000", // "communication" + "0x6170706c69636174696f6e000000000000000000000000000000000000000000" // "application" + ]; + + const modules = []; + + // Проверяем каждый модуль + for (const moduleId of standardModuleIds) { + try { + const isActive = await dle.isModuleActive(moduleId); + if (isActive) { + const moduleAddress = await dle.getModuleAddress(moduleId); + + // Получаем человекочитаемое название модуля + const moduleName = getModuleName(moduleId); + const moduleDescription = getModuleDescription(moduleId); + + modules.push({ + moduleId: moduleId, + moduleName: moduleName, + moduleDescription: moduleDescription, + moduleAddress: moduleAddress, + isActive: isActive, + deployedAt: new Date().toISOString() // В реальности нужно брать из событий + }); + + console.log(`[DLE Modules] Найден активный модуль: ${moduleName} по адресу ${moduleAddress}`); + } + } catch (error) { + console.log(`[DLE Modules] Ошибка при проверке модуля ${getModuleName(moduleId)}:`, error.message); + } + } + + console.log(`[DLE Modules] Всего найдено активных модулей в блокчейне: ${modules.length}`); + + res.json({ + success: true, + data: { + modules: modules, + modulesInitialized: modulesInitialized, + totalModules: standardModuleIds.length, + activeModules: modules.length + } + }); } - console.log(`[DLE Modules] Найдено активных модулей: ${modules.length}`); - - res.json({ - success: true, - data: { - modules: modules - } - }); - } catch (error) { console.error('[DLE Modules] Ошибка при получении всех модулей:', error); res.status(500).json({ @@ -337,15 +479,10 @@ async function getDeployedModulesInfo(dleAddress) { const path = require('path'); try { - // Ищем файл модулей для конкретного DLE - const deployDir = path.join(__dirname, '../temp'); - if (!fs.existsSync(deployDir)) { - return { modules: [], verification: {} }; - } - - // Ищем файл по адресу DLE + // Ищем файл модулей в правильной директории + const tempDir = path.join(__dirname, '../scripts/temp'); const modulesFileName = `modules-${dleAddress.toLowerCase()}.json`; - const modulesFilePath = path.join(deployDir, modulesFileName); + const modulesFilePath = path.join(tempDir, modulesFileName); if (!fs.existsSync(modulesFilePath)) { console.log(`[DLE Modules] Файл модулей не найден: ${modulesFileName}`); @@ -356,10 +493,26 @@ async function getDeployedModulesInfo(dleAddress) { const data = JSON.parse(fs.readFileSync(modulesFilePath, 'utf8')); console.log(`[DLE Modules] Загружена информация о модулях для DLE: ${dleAddress}`); + // Получаем статус верификации для каждого модуля + const modulesWithVerification = []; + + if (data.modules && Array.isArray(data.modules)) { + for (const networkModules of data.modules) { + if (networkModules.treasuryModule) { + modulesWithVerification.push({ + ...networkModules, + verificationStatus: data.verification?.[0]?.treasuryModule || 'pending' + }); + } + } + } + return { modules: data.modules || [], verification: data.verification || {}, - deployTimestamp: data.deployTimestamp + deployTimestamp: data.deployTimestamp, + networks: data.networks || [], // ✅ Добавляем поле networks + modulesWithVerification: modulesWithVerification }; } catch (error) { console.error(`Ошибка при чтении файла ${modulesFileName}:`, error); @@ -372,4 +525,404 @@ async function getDeployedModulesInfo(dleAddress) { } } +// Функция для определения названия сети по chainId +function getNetworkNameByChainId(chainId) { + const networkNames = { + 1: 'Ethereum Mainnet', + 5: 'Goerli', + 11155111: 'Sepolia', + 137: 'Polygon Mainnet', + 80001: 'Mumbai', + 56: 'BSC Mainnet', + 97: 'BSC Testnet', + 42161: 'Arbitrum One', + 421614: 'Arbitrum Sepolia', + 10: 'Optimism', + 11155420: 'Optimism Sepolia', + 8453: 'Base', + 84532: 'Base Sepolia' + }; + + return networkNames[chainId] || `Chain ID ${chainId}`; +} + +// Функция для получения модулей из файлов +async function getModulesFromFiles(dleAddress) { + const fs = require('fs'); + const path = require('path'); + + try { + // Ищем файл модулей в правильной директории + const tempDir = path.join(__dirname, '../scripts/temp'); + const modulesFileName = `modules-${dleAddress.toLowerCase()}.json`; + const modulesFilePath = path.join(tempDir, modulesFileName); + + if (!fs.existsSync(modulesFilePath)) { + console.log(`[DLE Modules] Файл модулей не найден: ${modulesFileName}`); + return []; + } + + try { + const data = JSON.parse(fs.readFileSync(modulesFilePath, 'utf8')); + console.log(`[DLE Modules] Загружена информация о модулях для DLE: ${dleAddress}`); + + const modules = []; + + // Обрабатываем модули из файла + if (data.modules && Array.isArray(data.modules)) { + for (const networkModules of data.modules) { + if (networkModules.treasuryModule) { + modules.push({ + moduleId: "0x7472656173757279000000000000000000000000000000000000000000000000", + moduleName: "TREASURY", + moduleDescription: "Казначейство DLE - управление финансами, депозиты, выводы, дивиденды", + moduleAddress: networkModules.treasuryModule, + isActive: true, + deployedAt: data.deployTimestamp + }); + } + + if (networkModules.timelockModule) { + modules.push({ + moduleId: "0x74696d656c6f636b000000000000000000000000000000000000000000000000", + moduleName: "TIMELOCK", + moduleDescription: "Модуль задержек исполнения - безопасность критических операций через таймлоки", + moduleAddress: networkModules.timelockModule, + isActive: true, + deployedAt: data.deployTimestamp + }); + } + + if (networkModules.dleReader) { + modules.push({ + moduleId: "0x726561646572000000000000000000000000000000000000000000000000000000", + moduleName: "READER", + moduleDescription: "Модуль чтения данных DLE - получение информации о контракте", + moduleAddress: networkModules.dleReader, + isActive: true, + deployedAt: data.deployTimestamp + }); + } + } + } + + // Убираем дубликаты (модули могут быть в нескольких сетях) + const uniqueModules = modules.filter((module, index, self) => + index === self.findIndex(m => m.moduleId === module.moduleId) + ); + + return uniqueModules; + + } catch (error) { + console.error(`Ошибка при чтении файла ${modulesFileName}:`, error); + return []; + } + + } catch (error) { + console.error('Ошибка при получении информации о модулях из файлов:', error); + return []; + } +} + +// Вспомогательные функции для получения названий и описаний модулей +function getModuleName(moduleId) { + const moduleNames = { + "0x7472656173757279000000000000000000000000000000000000000000000000": "TREASURY", + "0x74696d656c6f636b000000000000000000000000000000000000000000000000": "TIMELOCK", + "0x6d696e7400000000000000000000000000000000000000000000000000000000": "MINT", + "0x6275726e00000000000000000000000000000000000000000000000000000000": "BURN", + "0x6f7261636c650000000000000000000000000000000000000000000000000000": "ORACLE", + "0x696e6865726974616e6365000000000000000000000000000000000000000000": "INHERITANCE", + "0x636f6d6d756e69636174696f6e00000000000000000000000000000000000000": "COMMUNICATION", + "0x6170706c69636174696f6e000000000000000000000000000000000000000000": "APPLICATION" + }; + return moduleNames[moduleId] || "UNKNOWN"; +} + +function getModuleDescription(moduleId) { + const moduleDescriptions = { + "0x7472656173757279000000000000000000000000000000000000000000000000": "Казначейство DLE - управление финансами, депозиты, выводы, дивиденды", + "0x74696d656c6f636b000000000000000000000000000000000000000000000000": "Модуль задержек исполнения - безопасность критических операций через таймлоки", + "0x6d696e7400000000000000000000000000000000000000000000000000000000": "Модуль выпуска токенов - создание дополнительных токенов DLE через governance", + "0x6275726e00000000000000000000000000000000000000000000000000000000": "Модуль сжигания токенов - уменьшение общего предложения токенов DLE", + "0x6f7261636c650000000000000000000000000000000000000000000000000000": "Модуль оракулов - получение внешних данных для автоматизации DLE", + "0x696e6865726974616e6365000000000000000000000000000000000000000000": "Модуль наследования - передача прав и токенов между участниками DLE", + "0x636f6d6d756e69636174696f6e00000000000000000000000000000000000000": "Модуль коммуникации - уведомления и взаимодействие между участниками DLE", + "0x6170706c69636174696f6e000000000000000000000000000000000000000000": "Модуль заявок - обработка предложений и заявок участников DLE" + }; + return moduleDescriptions[moduleId] || "Описание не найдено"; +} + +// Верификация модуля на Etherscan +router.post('/verify-module', async (req, res) => { + try { + const { dleAddress, moduleId, moduleAddress, moduleName } = req.body; + + if (!dleAddress || !moduleId || !moduleAddress || !moduleName) { + return res.status(400).json({ + success: false, + error: 'Все параметры обязательны: dleAddress, moduleId, moduleAddress, moduleName' + }); + } + + console.log(`[DLE Modules] Верификация модуля ${moduleName} по адресу ${moduleAddress}`); + + // Получаем API ключ Etherscan из секретов + const { getSecret } = require('../services/secretStore'); + let apiKey = await getSecret('ETHERSCAN_V2_API_KEY'); + + if (!apiKey) { + return res.status(500).json({ + success: false, + error: 'API ключ Etherscan не найден в секретах' + }); + } + + // Определяем chainId (Sepolia) + const chainId = 11155111; // Sepolia testnet + + // Определяем имя контракта на основе moduleId + let contractName; + if (moduleId === "0x7472656173757279000000000000000000000000000000000000000000000000") { + contractName = "TreasuryModule"; + } else if (moduleId === "0x74696d656c6f636b000000000000000000000000000000000000000000000000") { + contractName = "TimelockModule"; + } else if (moduleId === "0x726561646572000000000000000000000000000000000000000000000000000000") { + contractName = "DLEReader"; + } else { + contractName = "UnknownModule"; + } + + console.log(`[DLE Modules] Верификация ${contractName} на Etherscan...`); + + // Импортируем сервис верификации + const etherscanV2 = require('../services/etherscanV2VerificationService'); + + // Получаем RPC URL для Sepolia + const rpcProviderService = require('../services/rpcProviderService'); + const rpcUrl = await rpcProviderService.getRpcUrlByChainId(chainId); + + if (!rpcUrl) { + return res.status(500).json({ + success: false, + error: 'RPC URL для Sepolia не найден' + }); + } + + // Получаем ABI и bytecode для модуля + const { ethers } = require('ethers'); + const provider = new ethers.JsonRpcProvider(rpcUrl); + + // Получаем код контракта для проверки существования + const code = await provider.getCode(moduleAddress); + + if (code === '0x') { + return res.status(400).json({ + success: false, + error: 'По указанному адресу нет контракта' + }); + } + + // Создаем стандартный JSON input для компиляции + const standardJsonInput = await createStandardJsonInput(contractName, moduleAddress, dleAddress, chainId); + + // Отправляем верификацию на Etherscan + const verificationResult = await etherscanV2.submitVerification({ + chainId: chainId, + contractAddress: moduleAddress, + contractName: `${contractName}.sol:${contractName}`, // Формат: filename.sol:contractname + compilerVersion: "v0.8.20+commit.a1b79de6", // Версия компилятора (точно как в основном контракте) + standardJsonInput: standardJsonInput.standardJsonInput, + constructorArgsHex: standardJsonInput.constructorArgsHex, + apiKey: apiKey + }); + + console.log(`[DLE Modules] Результат верификации:`, verificationResult); + + // Обновляем статус верификации в файле модулей + await updateModuleVerificationStatus(dleAddress, moduleId, 'success'); + + res.json({ + success: true, + data: { + message: `Модуль ${moduleName} успешно верифицирован`, + verificationResult: verificationResult, + contractName: contractName, + moduleAddress: moduleAddress + } + }); + + } catch (error) { + console.error('[DLE Modules] Ошибка верификации модуля:', error); + + // Обновляем статус верификации в файле модулей + if (req.body.dleAddress && req.body.moduleId) { + await updateModuleVerificationStatus(req.body.dleAddress, req.body.moduleId, 'failed'); + } + + res.status(500).json({ + success: false, + error: 'Ошибка верификации модуля: ' + error.message + }); + } +}); + +// Функция для обновления статуса верификации в файле модулей +async function updateModuleVerificationStatus(dleAddress, moduleId, status) { + try { + const fs = require('fs'); + const path = require('path'); + + const tempDir = path.join(__dirname, '../scripts/temp'); + const modulesFileName = `modules-${dleAddress.toLowerCase()}.json`; + const modulesFilePath = path.join(tempDir, modulesFileName); + + if (!fs.existsSync(modulesFilePath)) { + console.log(`[DLE Modules] Файл модулей не найден для обновления статуса: ${modulesFileName}`); + return; + } + + const data = JSON.parse(fs.readFileSync(modulesFilePath, 'utf8')); + + // Обновляем статус верификации для всех сетей + if (data.verification && Array.isArray(data.verification)) { + for (let i = 0; i < data.verification.length; i++) { + if (moduleId === "0x7472656173757279000000000000000000000000000000000000000000000000") { + data.verification[i].treasuryModule = status; + } else if (moduleId === "0x74696d656c6f636b000000000000000000000000000000000000000000000000") { + data.verification[i].timelockModule = status; + } else if (moduleId === "0x726561646572000000000000000000000000000000000000000000000000000000") { + data.verification[i].dleReader = status; + } + } + } + + // Записываем обновленные данные обратно в файл + fs.writeFileSync(modulesFilePath, JSON.stringify(data, null, 2)); + console.log(`[DLE Modules] Статус верификации обновлен для модуля ${moduleId}: ${status}`); + + } catch (error) { + console.error('[DLE Modules] Ошибка обновления статуса верификации:', error); + } +} + +// Функция для создания стандартного JSON input для верификации +async function createStandardJsonInput(contractName, moduleAddress, dleAddress, chainId) { + const fs = require('fs'); + const path = require('path'); + + try { + // Читаем исходный код контракта + let contractSource = ''; + let contractPath = ''; + + if (contractName === 'TreasuryModule') { + contractPath = path.join(__dirname, '../contracts/TreasuryModule.sol'); + } else if (contractName === 'TimelockModule') { + contractPath = path.join(__dirname, '../contracts/TimelockModule.sol'); + } else if (contractName === 'DLEReader') { + contractPath = path.join(__dirname, '../contracts/DLEReader.sol'); + } else { + throw new Error(`Неизвестный контракт: ${contractName}`); + } + + if (!fs.existsSync(contractPath)) { + throw new Error(`Файл контракта не найден: ${contractPath}`); + } + + contractSource = fs.readFileSync(contractPath, 'utf8'); + + // Определяем конструктор аргументы на основе типа контракта + let constructorArgs = []; + + if (contractName === 'TreasuryModule') { + // TreasuryModule: [dleAddress, chainId, emergencyAdmin] + // Нужно получить реальный emergencyAdmin из транзакции деплоя + let emergencyAdmin = dleAddress; // fallback + + try { + // Получаем emergencyAdmin из транзакции деплоя + const provider = new ethers.JsonRpcProvider(await require('../services/rpcProviderService').getRpcUrlByChainId(chainId)); + const history = await provider.getHistory(moduleAddress); + if (history.length > 0) { + const deployTx = history[0]; // Первая транзакция - это деплой + if (deployTx.from) { + emergencyAdmin = deployTx.from; // deployer становится emergencyAdmin + console.log(`[DLE Modules] Найден emergencyAdmin из транзакции деплоя: ${emergencyAdmin}`); + } + } + } catch (error) { + console.log(`[DLE Modules] Не удалось получить emergencyAdmin из транзакции: ${error.message}`); + } + + constructorArgs = [dleAddress, chainId.toString(), emergencyAdmin]; + } else if (contractName === 'TimelockModule') { + // TimelockModule: [dleAddress] + constructorArgs = [dleAddress]; + } else if (contractName === 'DLEReader') { + // DLEReader: [dleAddress] + constructorArgs = [dleAddress]; + } + + // Кодируем конструктор аргументы + const { ethers } = require('ethers'); + const abiCoder = new ethers.AbiCoder(); + + let constructorArgsHex = '0x'; + if (constructorArgs.length > 0) { + // Определяем типы параметров для каждого контракта + let paramTypes = []; + if (contractName === 'TreasuryModule') { + paramTypes = ['address', 'uint256', 'address']; + } else if (contractName === 'TimelockModule' || contractName === 'DLEReader') { + paramTypes = ['address']; + } + + constructorArgsHex = abiCoder.encode(paramTypes, constructorArgs); + } + + // Создаем стандартный JSON input + const standardJsonInput = { + language: "Solidity", + sources: { + [contractName + '.sol']: { + content: contractSource + } + }, + settings: { + optimizer: { + enabled: true, + runs: 200 + }, + evmVersion: "paris", + outputSelection: { + "*": { + "*": ["*"] + } + }, + libraries: {}, + remappings: [ + "@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/" + ] + } + }; + + console.log(`[DLE Modules] Создан standardJsonInput для ${contractName}:`, { + contractPath, + constructorArgs, + constructorArgsHex, + sourceLength: contractSource.length + }); + + return { + standardJsonInput: JSON.stringify(standardJsonInput), + constructorArgsHex: constructorArgsHex + }; + + } catch (error) { + console.error(`[DLE Modules] Ошибка создания standardJsonInput для ${contractName}:`, error); + throw error; + } +} + module.exports = router; diff --git a/backend/scripts/deploy/deploy-multichain.js b/backend/scripts/deploy/deploy-multichain.js index d0fde32..a032b8f 100644 --- a/backend/scripts/deploy/deploy-multichain.js +++ b/backend/scripts/deploy/deploy-multichain.js @@ -555,13 +555,52 @@ async function main() { console.log('MULTICHAIN_DEPLOY_RESULT', JSON.stringify(finalResults)); // Сохраняем информацию о модулях в отдельный файл для каждого DLE + // Добавляем информацию о сетях (chainId, rpcUrl) const modulesInfo = { dleAddress: uniqueAddresses[0], + networks: networks.map((rpcUrl, index) => ({ + rpcUrl: rpcUrl, + chainId: null, // Будет заполнено ниже + networkName: null // Будет заполнено ниже + })), modules: moduleResults, verification: verificationResults, deployTimestamp: new Date().toISOString() }; + // Получаем chainId для каждой сети + for (let i = 0; i < networks.length; i++) { + try { + const provider = new hre.ethers.JsonRpcProvider(networks[i]); + const network = await provider.getNetwork(); + modulesInfo.networks[i].chainId = Number(network.chainId); + + // Определяем название сети по chainId + const networkNames = { + 1: 'Ethereum Mainnet', + 5: 'Goerli', + 11155111: 'Sepolia', + 137: 'Polygon Mainnet', + 80001: 'Mumbai', + 56: 'BSC Mainnet', + 97: 'BSC Testnet', + 42161: 'Arbitrum One', + 421614: 'Arbitrum Sepolia', + 10: 'Optimism', + 11155420: 'Optimism Sepolia', + 8453: 'Base', + 84532: 'Base Sepolia' + }; + modulesInfo.networks[i].networkName = networkNames[Number(network.chainId)] || `Chain ID ${Number(network.chainId)}`; + + console.log(`[MULTI_DBG] Сеть ${i + 1}: chainId=${Number(network.chainId)}, name=${modulesInfo.networks[i].networkName}`); + } catch (error) { + console.error(`[MULTI_DBG] Ошибка получения chainId для сети ${i + 1}:`, error.message); + modulesInfo.networks[i].chainId = null; + modulesInfo.networks[i].networkName = `Сеть ${i + 1}`; + } + } + // Создаем директорию temp если её нет const tempDir = path.join(__dirname, '../temp'); if (!fs.existsSync(tempDir)) { diff --git a/backend/services/emailBot.js b/backend/services/emailBot.js index aa8fd51..fc53557 100644 --- a/backend/services/emailBot.js +++ b/backend/services/emailBot.js @@ -352,16 +352,6 @@ class EmailBotService { } // Проверяем, не обрабатывали ли мы уже это письмо - const existingResponse = await encryptedDb.getData('ai_responses', { - message_id: messageId - }); - - if (existingResponse.length > 0) { - // logger.info(`[EmailBot] Игнорируем дубликат письма от ${fromEmail} (Message-ID: ${messageId})`); // Убрано логирование email адреса - return; - } - - // Проверяем, не обрабатывали ли мы уже это письмо (улучшенная проверка) if (messageId) { try { // Проверяем, есть ли уже ответ от AI для этого письма diff --git a/frontend/src/views/smartcontracts/ModulesView.vue b/frontend/src/views/smartcontracts/ModulesView.vue index 3120dc3..ee31695 100644 --- a/frontend/src/views/smartcontracts/ModulesView.vue +++ b/frontend/src/views/smartcontracts/ModulesView.vue @@ -44,6 +44,9 @@