ваше сообщение коммита

This commit is contained in:
2025-05-14 20:12:41 +03:00
parent 35ec814b19
commit d79aab9352
141 changed files with 26454 additions and 1103 deletions

View File

@@ -7,7 +7,7 @@ const verificationService = require('./verification-service'); // Использ
const identityService = require('./identity-service'); // <-- ДОБАВЛЕН ИМПОРТ
const ADMIN_CONTRACTS = [
{ address: '0xd95a45fc46a7300e6022885afec3d618d7d3f27c', network: 'eth' },
{ address: '0xd95a45fc46a7300e6022885afec3d618d7d3f27c', network: 'ethereum' },
{ address: '0x4B294265720B09ca39BFBA18c7E368413c0f68eB', network: 'bsc' },
{ address: '0xdce769b847a0a697239777d0b1c7dd33b6012ba0', network: 'arbitrum' },
{ address: '0x351f59de4fedbdf7601f5592b93db3b9330c1c1d', network: 'polygon' },
@@ -17,8 +17,9 @@ const ERC20_ABI = ['function balanceOf(address owner) view returns (uint256)'];
class AuthService {
constructor() {
// Используем существующие переменные окружения с префиксом RPC_URL_
this.providers = {
eth: new ethers.JsonRpcProvider(process.env.RPC_URL_ETH),
ethereum: new ethers.JsonRpcProvider(process.env.RPC_URL_ETH), // Используем RPC_URL_ETH для ethereum
polygon: new ethers.JsonRpcProvider(process.env.RPC_URL_POLYGON),
bsc: new ethers.JsonRpcProvider(process.env.RPC_URL_BSC),
arbitrum: new ethers.JsonRpcProvider(process.env.RPC_URL_ARBITRUM),
@@ -233,7 +234,7 @@ class AuthService {
if (!address) {
logger.error('No address provided for getTokenBalances');
return {
eth: '0',
ethereum: '0',
bsc: '0',
arbitrum: '0',
polygon: '0',

View File

@@ -0,0 +1,252 @@
const { spawn } = require('child_process');
const path = require('path');
const fs = require('fs');
const { ethers } = require('ethers');
const logger = require('../utils/logger');
/**
* Сервис для управления DLE (Digital Legal Entity)
*/
class DLEService {
/**
* Создает новое DLE с заданными параметрами
* @param {Object} dleParams - Параметры DLE
* @returns {Promise<Object>} - Результат создания DLE
*/
async createDLE(dleParams) {
try {
logger.info('Начало создания DLE с параметрами:', dleParams);
// Валидация входных данных
this.validateDLEParams(dleParams);
// Подготовка параметров для деплоя
const deployParams = this.prepareDeployParams(dleParams);
// Сохраняем параметры во временный файл
const paramsFile = this.saveParamsToFile(deployParams);
// Копируем параметры во временный файл с предсказуемым именем
const tempParamsFile = path.join(__dirname, '../scripts/deploy/current-params.json');
logger.info(`Копирование параметров из ${paramsFile} в ${tempParamsFile}`);
const deployDir = path.dirname(tempParamsFile);
if (!fs.existsSync(deployDir)) {
fs.mkdirSync(deployDir, { recursive: true });
}
fs.copyFileSync(paramsFile, tempParamsFile);
logger.info(`Файл параметров скопирован успешно`);
// Запускаем скрипт без передачи аргументов командной строки
const result = await this.runDeployScript(paramsFile);
logger.info('DLE успешно создано:', result);
return result;
} catch (error) {
logger.error('Ошибка при создании DLE:', error);
throw error;
}
}
/**
* Валидирует параметры DLE
* @param {Object} params - Параметры DLE
*/
validateDLEParams(params) {
const requiredFields = [
'name', 'symbol', 'location', 'isicCodes',
'partners', 'amounts', 'minTimelockDelay',
'votingDelay', 'votingPeriod', 'proposalThreshold', 'quorumPercentage'
];
for (const field of requiredFields) {
if (params[field] === undefined) {
throw new Error(`Отсутствует обязательный параметр: ${field}`);
}
}
if (params.partners.length !== params.amounts.length) {
throw new Error('Количество партнеров должно соответствовать количеству сумм распределения');
}
if (params.partners.length === 0) {
throw new Error('Должен быть указан хотя бы один партнер');
}
if (params.quorumPercentage > 100) {
throw new Error('Процент кворума не может превышать 100%');
}
}
/**
* Подготавливает параметры для деплоя
* @param {Object} params - Параметры DLE
* @returns {Object} - Подготовленные параметры
*/
prepareDeployParams(params) {
// Создаем копию объекта, чтобы не изменять исходный
const deployParams = { ...params };
// Преобразуем суммы из строк или чисел в BigNumber, если нужно
deployParams.amounts = params.amounts.map(amount => {
if (typeof amount === 'string' && !amount.startsWith('0x')) {
return ethers.parseEther(amount).toString();
}
return amount.toString();
});
// Преобразуем proposalThreshold в BigNumber, если нужно
if (typeof deployParams.proposalThreshold === 'string' && !deployParams.proposalThreshold.startsWith('0x')) {
deployParams.proposalThreshold = ethers.parseEther(deployParams.proposalThreshold).toString();
} else {
deployParams.proposalThreshold = deployParams.proposalThreshold.toString();
}
return deployParams;
}
/**
* Сохраняет параметры деплоя во временный файл
* @param {Object} params - Параметры деплоя
* @returns {string} - Путь к файлу с параметрами
*/
saveParamsToFile(params) {
const tempDir = path.join(__dirname, '../temp');
if (!fs.existsSync(tempDir)) {
fs.mkdirSync(tempDir, { recursive: true });
}
const fileName = `dle-params-${Date.now()}.json`;
const filePath = path.join(tempDir, fileName);
fs.writeFileSync(filePath, JSON.stringify(params, null, 2));
return filePath;
}
/**
* Запускает скрипт деплоя DLE
* @param {string} paramsFile - Путь к файлу с параметрами
* @returns {Promise<Object>} - Результат деплоя
*/
runDeployScript(paramsFile) {
return new Promise((resolve, reject) => {
// Путь к новому скрипту для ручного деплоя (без фабрики)
const scriptPath = path.join(__dirname, '../scripts/deploy/create-dle-manual.js');
// Проверяем, существует ли скрипт
if (!fs.existsSync(scriptPath)) {
reject(new Error('Скрипт деплоя не найден: ' + scriptPath));
return;
}
// Запускаем скрипт без передачи аргументов командной строки
const hardhatProcess = spawn('npx', ['hardhat', 'run', scriptPath, '--network', 'sepolia'], {
cwd: path.join(__dirname, '..'),
env: { ...process.env },
stdio: 'pipe'
});
let stdout = '';
let stderr = '';
hardhatProcess.stdout.on('data', (data) => {
const output = data.toString();
stdout += output;
logger.debug(`[Hardhat] ${output}`);
});
hardhatProcess.stderr.on('data', (data) => {
const output = data.toString();
stderr += output;
logger.error(`[Hardhat Error] ${output}`);
});
hardhatProcess.on('close', (code) => {
if (code !== 0) {
logger.error(`Скрипт деплоя завершился с кодом: ${code}`);
reject(new Error(`Ошибка деплоя: ${stderr}`));
return;
}
// Пытаемся извлечь адреса контрактов из вывода
try {
const tokenAddressMatch = stdout.match(/Адрес токена: (0x[a-fA-F0-9]{40})/);
const timelockAddressMatch = stdout.match(/Адрес таймлока: (0x[a-fA-F0-9]{40})/);
const governorAddressMatch = stdout.match(/Адрес контракта Governor: (0x[a-fA-F0-9]{40})/);
if (tokenAddressMatch && timelockAddressMatch && governorAddressMatch) {
resolve({
tokenAddress: tokenAddressMatch[1],
timelockAddress: timelockAddressMatch[1],
governorAddress: governorAddressMatch[1],
success: true
});
} else {
// Если не удалось извлечь адреса, ищем файл с результатами
const dlesDir = path.join(__dirname, '../contracts-data/dles');
if (fs.existsSync(dlesDir)) {
const files = fs.readdirSync(dlesDir);
if (files.length > 0) {
// Берем самый свежий файл
const latestFile = files
.map(f => ({ name: f, time: fs.statSync(path.join(dlesDir, f)).mtime.getTime() }))
.sort((a, b) => b.time - a.time)[0].name;
const dleData = JSON.parse(fs.readFileSync(path.join(dlesDir, latestFile), 'utf8'));
resolve({
...dleData,
success: true
});
} else {
reject(new Error('Не удалось найти информацию о созданном DLE'));
}
} else {
reject(new Error('Не удалось найти директорию с результатами создания DLE'));
}
}
} catch (error) {
logger.error('Ошибка при извлечении результатов деплоя:', error);
reject(error);
}
});
});
}
/**
* Получает список всех созданных DLE
* @returns {Array<Object>} - Список DLE
*/
getAllDLEs() {
try {
const dlesDir = path.join(__dirname, '../contracts-data/dles');
if (!fs.existsSync(dlesDir)) {
return [];
}
const files = fs.readdirSync(dlesDir);
return files
.filter(file => file.endsWith('.json') && file !== 'test.json' && file !== 'node-test.json')
.map(file => {
try {
const data = JSON.parse(fs.readFileSync(path.join(dlesDir, file), 'utf8'));
// Добавляем имя файла к данным DLE для возможности удаления пустых DLE
return { ...data, _fileName: file };
} catch (error) {
logger.error(`Ошибка при чтении файла ${file}:`, error);
// Для поврежденных файлов возвращаем минимальную информацию
return {
_fileName: file,
_corrupted: true
};
}
});
} catch (error) {
logger.error('Ошибка при получении списка DLE:', error);
throw error;
}
}
}
module.exports = new DLEService();