ваше сообщение коммита
This commit is contained in:
@@ -1,442 +1,124 @@
|
||||
/**
|
||||
* 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');
|
||||
const deployParamsService = require('../services/deployParamsService');
|
||||
|
||||
// Получить поддерживаемые сети
|
||||
router.post('/get-supported-chains', async (req, res) => {
|
||||
/**
|
||||
* Получить адрес контракта в указанной сети для мультичейн голосования
|
||||
* POST /api/dle-core/get-multichain-contracts
|
||||
*/
|
||||
router.post('/get-multichain-contracts', async (req, res) => {
|
||||
try {
|
||||
const { dleAddress } = req.body;
|
||||
const { originalContract, targetChainId } = req.body;
|
||||
|
||||
if (!dleAddress) {
|
||||
console.log('🔍 [MULTICHAIN] Поиск контракта для мультичейн голосования:', {
|
||||
originalContract,
|
||||
targetChainId
|
||||
});
|
||||
|
||||
if (!originalContract || !targetChainId) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Адрес DLE обязателен'
|
||||
error: 'Не указан originalContract или targetChainId'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`[DLE Multichain] Получение поддерживаемых сетей для DLE: ${dleAddress}`);
|
||||
|
||||
const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
|
||||
if (!rpcUrl) {
|
||||
|
||||
// Ищем контракт в указанной сети
|
||||
// Для мультичейн контрактов с одинаковым адресом (детерминированный деплой)
|
||||
// или контракты в разных сетях с разными адресами
|
||||
|
||||
// Сначала проверяем, есть ли контракт с таким же адресом в целевой сети
|
||||
const contractsInTargetNetwork = await deployParamsService.getContractsByChainId(targetChainId);
|
||||
|
||||
console.log('📊 [MULTICHAIN] Контракты в целевой сети:', contractsInTargetNetwork);
|
||||
|
||||
// Ищем контракт в целевой сети (все контракты в targetChainId уже отфильтрованы)
|
||||
const targetContract = contractsInTargetNetwork[0]; // Берем первый контракт в целевой сети
|
||||
|
||||
if (targetContract) {
|
||||
console.log('✅ [MULTICHAIN] Найден контракт в целевой сети:', targetContract.dleAddress);
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
contractAddress: targetContract.dleAddress,
|
||||
chainId: targetChainId,
|
||||
source: 'database'
|
||||
});
|
||||
}
|
||||
|
||||
// Если не найден контракт в целевой сети, проверяем мультичейн развертывание
|
||||
// с одинаковым адресом (CREATE2)
|
||||
const { ethers } = require('ethers');
|
||||
|
||||
// Получаем RPC URL из параметров деплоя
|
||||
let rpcUrl;
|
||||
try {
|
||||
// Получаем последние параметры деплоя
|
||||
const latestParams = await deployParamsService.getLatestDeployParams(1);
|
||||
if (latestParams.length > 0) {
|
||||
const params = latestParams[0];
|
||||
const rpcUrls = params.rpcUrls || params.rpc_urls || {};
|
||||
rpcUrl = rpcUrls[targetChainId];
|
||||
}
|
||||
|
||||
// Если не найден в параметрах, используем fallback
|
||||
if (!rpcUrl) {
|
||||
const fallbackConfigs = {
|
||||
'11155111': 'https://1rpc.io/sepolia',
|
||||
'17000': 'https://ethereum-holesky.publicnode.com',
|
||||
'421614': 'https://sepolia-rollup.arbitrum.io/rpc',
|
||||
'84532': 'https://sepolia.base.org'
|
||||
};
|
||||
rpcUrl = fallbackConfigs[targetChainId];
|
||||
}
|
||||
|
||||
if (!rpcUrl) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: `Неподдерживаемая сеть: ${targetChainId}`
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Ошибка получения RPC URL:', error);
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
error: 'RPC URL для Sepolia не найден'
|
||||
error: 'Ошибка получения конфигурации сети'
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
const dleAbi = [
|
||||
"function getSupportedChainCount() external view returns (uint256)",
|
||||
"function getSupportedChainId(uint256 _index) external view returns (uint256)"
|
||||
];
|
||||
|
||||
const dle = new ethers.Contract(dleAddress, dleAbi, provider);
|
||||
|
||||
// Получаем количество поддерживаемых сетей
|
||||
const chainCount = await dle.getSupportedChainCount();
|
||||
|
||||
// Получаем ID каждой сети
|
||||
const supportedChains = [];
|
||||
for (let i = 0; i < Number(chainCount); i++) {
|
||||
const chainId = await dle.getSupportedChainId(i);
|
||||
supportedChains.push(chainId);
|
||||
}
|
||||
|
||||
console.log(`[DLE Multichain] Поддерживаемые сети:`, supportedChains);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
chains: supportedChains.map(chainId => Number(chainId))
|
||||
try {
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
const contractCode = await provider.getCode(originalContract);
|
||||
|
||||
if (contractCode && contractCode !== '0x') {
|
||||
console.log('✅ [MULTICHAIN] Контракт существует в целевой сети с тем же адресом (CREATE2)');
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
contractAddress: originalContract,
|
||||
chainId: targetChainId,
|
||||
source: 'blockchain'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('[DLE Multichain] Ошибка при получении поддерживаемых сетей:', error);
|
||||
res.status(500).json({
|
||||
} catch (blockchainError) {
|
||||
console.warn('⚠️ [MULTICHAIN] Ошибка проверки контракта в блокчейне:', blockchainError.message);
|
||||
}
|
||||
|
||||
// Контракт не найден
|
||||
console.log('❌ [MULTICHAIN] Контракт не найден в целевой сети');
|
||||
|
||||
return res.json({
|
||||
success: false,
|
||||
error: 'Ошибка при получении поддерживаемых сетей: ' + error.message
|
||||
error: 'Контракт не найден в целевой сети'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ [MULTICHAIN] Ошибка поиска мультичейн контракта:', error);
|
||||
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
error: 'Внутренняя ошибка сервера'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Проверить поддержку сети
|
||||
router.post('/is-chain-supported', async (req, res) => {
|
||||
try {
|
||||
const { dleAddress, chainId } = req.body;
|
||||
|
||||
if (!dleAddress || chainId === undefined) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Адрес DLE и ID сети обязательны'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`[DLE Multichain] Проверка поддержки сети ${chainId} для 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 isChainSupported(uint256 _chainId) external view returns (bool)"
|
||||
];
|
||||
|
||||
const dle = new ethers.Contract(dleAddress, dleAbi, provider);
|
||||
|
||||
// Проверяем поддержку сети
|
||||
const isSupported = await dle.isChainSupported(chainId);
|
||||
|
||||
console.log(`[DLE Multichain] Поддержка сети ${chainId}: ${isSupported}`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
chainId: Number(chainId),
|
||||
isSupported: isSupported
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('[DLE Multichain] Ошибка при проверке поддержки сети:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Ошибка при проверке поддержки сети: ' + error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Получить количество поддерживаемых сетей
|
||||
router.post('/get-supported-chain-count', async (req, res) => {
|
||||
try {
|
||||
const { dleAddress } = req.body;
|
||||
|
||||
if (!dleAddress) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Адрес DLE обязателен'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`[DLE Multichain] Получение количества поддерживаемых сетей для 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 getSupportedChainCount() external view returns (uint256)"
|
||||
];
|
||||
|
||||
const dle = new ethers.Contract(dleAddress, dleAbi, provider);
|
||||
|
||||
// Получаем количество поддерживаемых сетей
|
||||
const count = await dle.getSupportedChainCount();
|
||||
|
||||
console.log(`[DLE Multichain] Количество поддерживаемых сетей: ${count}`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
count: Number(count)
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('[DLE Multichain] Ошибка при получении количества поддерживаемых сетей:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Ошибка при получении количества поддерживаемых сетей: ' + error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Получить ID сети по индексу
|
||||
router.post('/get-supported-chain-id', async (req, res) => {
|
||||
try {
|
||||
const { dleAddress, index } = req.body;
|
||||
|
||||
if (!dleAddress || index === undefined) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Адрес DLE и индекс обязательны'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`[DLE Multichain] Получение ID сети по индексу ${index} для 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 getSupportedChainId(uint256 _index) external view returns (uint256)"
|
||||
];
|
||||
|
||||
const dle = new ethers.Contract(dleAddress, dleAbi, provider);
|
||||
|
||||
// Получаем ID сети по индексу
|
||||
const chainId = await dle.getSupportedChainId(index);
|
||||
|
||||
console.log(`[DLE Multichain] ID сети по индексу ${index}: ${chainId}`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
index: Number(index),
|
||||
chainId: Number(chainId)
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('[DLE Multichain] Ошибка при получении ID сети по индексу:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Ошибка при получении ID сети по индексу: ' + error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Проверить подключение к сети
|
||||
router.post('/check-chain-connection', async (req, res) => {
|
||||
try {
|
||||
const { dleAddress, chainId } = req.body;
|
||||
|
||||
if (!dleAddress || chainId === undefined) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Адрес DLE и ID сети обязательны'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`[DLE Multichain] Проверка подключения к сети ${chainId} для 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 checkChainConnection(uint256 _chainId) external view returns (bool)"
|
||||
];
|
||||
|
||||
const dle = new ethers.Contract(dleAddress, dleAbi, provider);
|
||||
|
||||
// Проверяем подключение к сети
|
||||
const isAvailable = await dle.checkChainConnection(chainId);
|
||||
|
||||
console.log(`[DLE Multichain] Подключение к сети ${chainId}: ${isAvailable}`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
chainId: Number(chainId),
|
||||
isAvailable: isAvailable
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('[DLE Multichain] Ошибка при проверке подключения к сети:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Ошибка при проверке подключения к сети: ' + error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Проверить готовность к синхронизации
|
||||
router.post('/check-sync-readiness', async (req, res) => {
|
||||
try {
|
||||
const { dleAddress, proposalId } = req.body;
|
||||
|
||||
if (!dleAddress || proposalId === undefined) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Адрес DLE и ID предложения обязательны'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`[DLE Multichain] Проверка готовности к синхронизации предложения ${proposalId} для 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 checkSyncReadiness(uint256 _proposalId) external view returns (bool)"
|
||||
];
|
||||
|
||||
const dle = new ethers.Contract(dleAddress, dleAbi, provider);
|
||||
|
||||
// Проверяем готовность к синхронизации
|
||||
const allChainsReady = await dle.checkSyncReadiness(proposalId);
|
||||
|
||||
console.log(`[DLE Multichain] Готовность к синхронизации предложения ${proposalId}: ${allChainsReady}`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
proposalId: Number(proposalId),
|
||||
allChainsReady: allChainsReady
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('[DLE Multichain] Ошибка при проверке готовности к синхронизации:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Ошибка при проверке готовности к синхронизации: ' + error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Синхронизировать во все сети
|
||||
router.post('/sync-to-all-chains', async (req, res) => {
|
||||
try {
|
||||
const { dleAddress, proposalId, userAddress, privateKey } = req.body;
|
||||
|
||||
if (!dleAddress || proposalId === undefined || !userAddress || !privateKey) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Все поля обязательны, включая приватный ключ'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`[DLE Multichain] Синхронизация предложения ${proposalId} во все сети для 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 wallet = new ethers.Wallet(privateKey, provider);
|
||||
|
||||
const dleAbi = [
|
||||
"function syncToAllChains(uint256 _proposalId) external"
|
||||
];
|
||||
|
||||
const dle = new ethers.Contract(dleAddress, dleAbi, wallet);
|
||||
|
||||
// Синхронизируем во все сети
|
||||
const tx = await dle.syncToAllChains(proposalId);
|
||||
const receipt = await tx.wait();
|
||||
|
||||
console.log(`[DLE Multichain] Синхронизация выполнена:`, receipt);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
transactionHash: receipt.hash
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('[DLE Multichain] Ошибка при синхронизации во все сети:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Ошибка при синхронизации во все сети: ' + error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Исполнить предложение по подписям
|
||||
router.post('/execute-proposal-by-signatures', async (req, res) => {
|
||||
try {
|
||||
const { dleAddress, proposalId, signatures, userAddress, privateKey } = req.body;
|
||||
|
||||
if (!dleAddress || proposalId === undefined || !signatures || !userAddress || !privateKey) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Все поля обязательны, включая приватный ключ'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`[DLE Multichain] Исполнение предложения ${proposalId} по подписям для 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 wallet = new ethers.Wallet(privateKey, provider);
|
||||
|
||||
const dleAbi = [
|
||||
"function executeProposalBySignatures(uint256 _proposalId, bytes[] calldata _signatures) external"
|
||||
];
|
||||
|
||||
const dle = new ethers.Contract(dleAddress, dleAbi, wallet);
|
||||
|
||||
// Исполняем предложение по подписям
|
||||
const tx = await dle.executeProposalBySignatures(proposalId, signatures);
|
||||
const receipt = await tx.wait();
|
||||
|
||||
console.log(`[DLE Multichain] Предложение исполнено по подписям:`, receipt);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
transactionHash: receipt.hash
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('[DLE Multichain] Ошибка при исполнении предложения по подписям:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Ошибка при исполнении предложения по подписям: ' + error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user