ваше сообщение коммита
This commit is contained in:
@@ -64,7 +64,8 @@ router.post('/read-dle-info', async (req, res) => {
|
|||||||
"function totalSupply() external view returns (uint256)",
|
"function totalSupply() external view returns (uint256)",
|
||||||
"function balanceOf(address account) external view returns (uint256)",
|
"function balanceOf(address account) external view returns (uint256)",
|
||||||
"function quorumPercentage() external view returns (uint256)",
|
"function quorumPercentage() external view returns (uint256)",
|
||||||
"function getCurrentChainId() external view returns (uint256)"
|
"function getCurrentChainId() external view returns (uint256)",
|
||||||
|
"function logoURI() external view returns (string memory)"
|
||||||
];
|
];
|
||||||
|
|
||||||
const dle = new ethers.Contract(dleAddress, dleAbi, provider);
|
const dle = new ethers.Contract(dleAddress, dleAbi, provider);
|
||||||
@@ -74,22 +75,103 @@ router.post('/read-dle-info', async (req, res) => {
|
|||||||
const totalSupply = await dle.totalSupply();
|
const totalSupply = await dle.totalSupply();
|
||||||
const quorumPercentage = await dle.quorumPercentage();
|
const quorumPercentage = await dle.quorumPercentage();
|
||||||
const currentChainId = await dle.getCurrentChainId();
|
const currentChainId = await dle.getCurrentChainId();
|
||||||
|
|
||||||
// Проверяем баланс создателя (адрес, который деплоил контракт)
|
// Читаем логотип
|
||||||
const deployer = "0xF45aa4917b3775bA37f48Aeb3dc1a943561e9e0B";
|
let logoURI = '';
|
||||||
const deployerBalance = await dle.balanceOf(deployer);
|
try {
|
||||||
|
logoURI = await dle.logoURI();
|
||||||
// Определяем количество участников (держателей токенов)
|
} catch (error) {
|
||||||
let participantCount = 0;
|
console.log(`[Blockchain] Ошибка при чтении logoURI:`, error.message);
|
||||||
if (deployerBalance > 0) {
|
|
||||||
participantCount++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Проверяем, есть ли другие держатели токенов
|
// Получаем информацию о партнерах из блокчейна
|
||||||
// Для простоты считаем, что если создатель имеет меньше 100% токенов, то есть другие участники
|
const partnerBalances = [];
|
||||||
const deployerPercentage = (Number(deployerBalance) / Number(totalSupply)) * 100;
|
let participantCount = 0;
|
||||||
if (deployerPercentage < 100) {
|
|
||||||
participantCount = Math.max(participantCount, 2); // Минимум 2 участника
|
// Получаем события InitialTokensDistributed для определения партнеров
|
||||||
|
try {
|
||||||
|
// Получаем последние блоки для поиска событий
|
||||||
|
const currentBlock = await provider.getBlockNumber();
|
||||||
|
const fromBlock = Math.max(0, currentBlock - 10000); // Ищем в последних 10000 блоках
|
||||||
|
|
||||||
|
// ABI для события InitialTokensDistributed
|
||||||
|
const eventAbi = [
|
||||||
|
"event InitialTokensDistributed(address[] partners, uint256[] amounts)"
|
||||||
|
];
|
||||||
|
|
||||||
|
const dleWithEvents = new ethers.Contract(dleAddress, [...dleAbi, ...eventAbi], provider);
|
||||||
|
|
||||||
|
// Ищем события InitialTokensDistributed
|
||||||
|
const events = await dleWithEvents.queryFilter(
|
||||||
|
dleWithEvents.filters.InitialTokensDistributed(),
|
||||||
|
fromBlock,
|
||||||
|
currentBlock
|
||||||
|
);
|
||||||
|
|
||||||
|
if (events.length > 0) {
|
||||||
|
// Берем последнее событие
|
||||||
|
const lastEvent = events[events.length - 1];
|
||||||
|
const partners = lastEvent.args.partners;
|
||||||
|
const amounts = lastEvent.args.amounts;
|
||||||
|
|
||||||
|
for (let i = 0; i < partners.length; i++) {
|
||||||
|
const partnerAddress = partners[i];
|
||||||
|
const amount = amounts[i];
|
||||||
|
|
||||||
|
// Проверяем текущий баланс
|
||||||
|
const currentBalance = await dle.balanceOf(partnerAddress);
|
||||||
|
if (Number(currentBalance) > 0) {
|
||||||
|
participantCount++;
|
||||||
|
partnerBalances.push({
|
||||||
|
address: partnerAddress,
|
||||||
|
balance: ethers.formatUnits(currentBalance, 18),
|
||||||
|
percentage: (Number(currentBalance) / Number(totalSupply)) * 100,
|
||||||
|
initialAmount: ethers.formatUnits(amount, 18)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`[Blockchain] Ошибка при получении событий партнеров:`, error.message);
|
||||||
|
|
||||||
|
// Fallback: ищем держателей токенов через события Transfer
|
||||||
|
try {
|
||||||
|
const currentBlock = await provider.getBlockNumber();
|
||||||
|
const fromBlock = Math.max(0, currentBlock - 10000);
|
||||||
|
|
||||||
|
const transferEventAbi = [
|
||||||
|
"event Transfer(address indexed from, address indexed to, uint256 value)"
|
||||||
|
];
|
||||||
|
|
||||||
|
const dleWithTransferEvents = new ethers.Contract(dleAddress, [...dleAbi, ...transferEventAbi], provider);
|
||||||
|
|
||||||
|
// Ищем события Transfer с from = address(0) (mint события)
|
||||||
|
const mintEvents = await dleWithTransferEvents.queryFilter(
|
||||||
|
dleWithTransferEvents.filters.Transfer(ethers.ZeroAddress),
|
||||||
|
fromBlock,
|
||||||
|
currentBlock
|
||||||
|
);
|
||||||
|
|
||||||
|
const uniqueRecipients = new Set();
|
||||||
|
for (const event of mintEvents) {
|
||||||
|
uniqueRecipients.add(event.args.to);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем текущие балансы всех получателей
|
||||||
|
for (const recipient of uniqueRecipients) {
|
||||||
|
const balance = await dle.balanceOf(recipient);
|
||||||
|
if (Number(balance) > 0) {
|
||||||
|
participantCount++;
|
||||||
|
partnerBalances.push({
|
||||||
|
address: recipient,
|
||||||
|
balance: ethers.formatUnits(balance, 18),
|
||||||
|
percentage: (Number(balance) / Number(totalSupply)) * 100
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (fallbackError) {
|
||||||
|
console.log(`[Blockchain] Ошибка при fallback поиске партнеров:`, fallbackError.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const blockchainData = {
|
const blockchainData = {
|
||||||
@@ -106,7 +188,8 @@ router.post('/read-dle-info', async (req, res) => {
|
|||||||
creationTimestamp: Number(dleInfo.creationTimestamp),
|
creationTimestamp: Number(dleInfo.creationTimestamp),
|
||||||
isActive: dleInfo.isActive,
|
isActive: dleInfo.isActive,
|
||||||
totalSupply: ethers.formatUnits(totalSupply, 18),
|
totalSupply: ethers.formatUnits(totalSupply, 18),
|
||||||
deployerBalance: ethers.formatUnits(deployerBalance, 18),
|
partnerBalances: partnerBalances, // Информация о партнерах и их балансах
|
||||||
|
logoURI: logoURI, // URL логотипа токена
|
||||||
quorumPercentage: Number(quorumPercentage),
|
quorumPercentage: Number(quorumPercentage),
|
||||||
currentChainId: Number(currentChainId),
|
currentChainId: Number(currentChainId),
|
||||||
rpcUsed: rpcUrl,
|
rpcUsed: rpcUrl,
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ router.post('/read-dle-info', async (req, res) => {
|
|||||||
"function totalSupply() external view returns (uint256)",
|
"function totalSupply() external view returns (uint256)",
|
||||||
"function balanceOf(address account) external view returns (uint256)",
|
"function balanceOf(address account) external view returns (uint256)",
|
||||||
"function quorumPercentage() external view returns (uint256)",
|
"function quorumPercentage() external view returns (uint256)",
|
||||||
"function getCurrentChainId() external view returns (uint256)"
|
"function getCurrentChainId() external view returns (uint256)",
|
||||||
|
"function logoURI() external view returns (string memory)"
|
||||||
];
|
];
|
||||||
|
|
||||||
const dle = new ethers.Contract(dleAddress, dleAbi, provider);
|
const dle = new ethers.Contract(dleAddress, dleAbi, provider);
|
||||||
@@ -56,22 +57,103 @@ router.post('/read-dle-info', async (req, res) => {
|
|||||||
const totalSupply = await dle.totalSupply();
|
const totalSupply = await dle.totalSupply();
|
||||||
const quorumPercentage = await dle.quorumPercentage();
|
const quorumPercentage = await dle.quorumPercentage();
|
||||||
const currentChainId = await dle.getCurrentChainId();
|
const currentChainId = await dle.getCurrentChainId();
|
||||||
|
|
||||||
// Проверяем баланс создателя (адрес, который деплоил контракт)
|
// Читаем логотип
|
||||||
const deployer = "0xF45aa4917b3775bA37f48Aeb3dc1a943561e9e0B";
|
let logoURI = '';
|
||||||
const deployerBalance = await dle.balanceOf(deployer);
|
try {
|
||||||
|
logoURI = await dle.logoURI();
|
||||||
// Определяем количество участников (держателей токенов)
|
} catch (error) {
|
||||||
let participantCount = 0;
|
console.log(`[DLE Core] Ошибка при чтении logoURI:`, error.message);
|
||||||
if (deployerBalance > 0) {
|
|
||||||
participantCount++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Проверяем, есть ли другие держатели токенов
|
// Получаем информацию о партнерах из блокчейна
|
||||||
// Для простоты считаем, что если создатель имеет меньше 100% токенов, то есть другие участники
|
const partnerBalances = [];
|
||||||
const deployerPercentage = (Number(deployerBalance) / Number(totalSupply)) * 100;
|
let participantCount = 0;
|
||||||
if (deployerPercentage < 100) {
|
|
||||||
participantCount = Math.max(participantCount, 2); // Минимум 2 участника
|
// Получаем события InitialTokensDistributed для определения партнеров
|
||||||
|
try {
|
||||||
|
// Получаем последние блоки для поиска событий
|
||||||
|
const currentBlock = await provider.getBlockNumber();
|
||||||
|
const fromBlock = Math.max(0, currentBlock - 10000); // Ищем в последних 10000 блоках
|
||||||
|
|
||||||
|
// ABI для события InitialTokensDistributed
|
||||||
|
const eventAbi = [
|
||||||
|
"event InitialTokensDistributed(address[] partners, uint256[] amounts)"
|
||||||
|
];
|
||||||
|
|
||||||
|
const dleWithEvents = new ethers.Contract(dleAddress, [...dleAbi, ...eventAbi], provider);
|
||||||
|
|
||||||
|
// Ищем события InitialTokensDistributed
|
||||||
|
const events = await dleWithEvents.queryFilter(
|
||||||
|
dleWithEvents.filters.InitialTokensDistributed(),
|
||||||
|
fromBlock,
|
||||||
|
currentBlock
|
||||||
|
);
|
||||||
|
|
||||||
|
if (events.length > 0) {
|
||||||
|
// Берем последнее событие
|
||||||
|
const lastEvent = events[events.length - 1];
|
||||||
|
const partners = lastEvent.args.partners;
|
||||||
|
const amounts = lastEvent.args.amounts;
|
||||||
|
|
||||||
|
for (let i = 0; i < partners.length; i++) {
|
||||||
|
const partnerAddress = partners[i];
|
||||||
|
const amount = amounts[i];
|
||||||
|
|
||||||
|
// Проверяем текущий баланс
|
||||||
|
const currentBalance = await dle.balanceOf(partnerAddress);
|
||||||
|
if (Number(currentBalance) > 0) {
|
||||||
|
participantCount++;
|
||||||
|
partnerBalances.push({
|
||||||
|
address: partnerAddress,
|
||||||
|
balance: ethers.formatUnits(currentBalance, 18),
|
||||||
|
percentage: (Number(currentBalance) / Number(totalSupply)) * 100,
|
||||||
|
initialAmount: ethers.formatUnits(amount, 18)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`[DLE Core] Ошибка при получении событий партнеров:`, error.message);
|
||||||
|
|
||||||
|
// Fallback: ищем держателей токенов через события Transfer
|
||||||
|
try {
|
||||||
|
const currentBlock = await provider.getBlockNumber();
|
||||||
|
const fromBlock = Math.max(0, currentBlock - 10000);
|
||||||
|
|
||||||
|
const transferEventAbi = [
|
||||||
|
"event Transfer(address indexed from, address indexed to, uint256 value)"
|
||||||
|
];
|
||||||
|
|
||||||
|
const dleWithTransferEvents = new ethers.Contract(dleAddress, [...dleAbi, ...transferEventAbi], provider);
|
||||||
|
|
||||||
|
// Ищем события Transfer с from = address(0) (mint события)
|
||||||
|
const mintEvents = await dleWithTransferEvents.queryFilter(
|
||||||
|
dleWithTransferEvents.filters.Transfer(ethers.ZeroAddress),
|
||||||
|
fromBlock,
|
||||||
|
currentBlock
|
||||||
|
);
|
||||||
|
|
||||||
|
const uniqueRecipients = new Set();
|
||||||
|
for (const event of mintEvents) {
|
||||||
|
uniqueRecipients.add(event.args.to);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем текущие балансы всех получателей
|
||||||
|
for (const recipient of uniqueRecipients) {
|
||||||
|
const balance = await dle.balanceOf(recipient);
|
||||||
|
if (Number(balance) > 0) {
|
||||||
|
participantCount++;
|
||||||
|
partnerBalances.push({
|
||||||
|
address: recipient,
|
||||||
|
balance: ethers.formatUnits(balance, 18),
|
||||||
|
percentage: (Number(balance) / Number(totalSupply)) * 100
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (fallbackError) {
|
||||||
|
console.log(`[DLE Core] Ошибка при fallback поиске партнеров:`, fallbackError.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const blockchainData = {
|
const blockchainData = {
|
||||||
@@ -87,7 +169,8 @@ router.post('/read-dle-info', async (req, res) => {
|
|||||||
creationTimestamp: Number(dleInfo.creationTimestamp),
|
creationTimestamp: Number(dleInfo.creationTimestamp),
|
||||||
isActive: dleInfo.isActive,
|
isActive: dleInfo.isActive,
|
||||||
totalSupply: ethers.formatUnits(totalSupply, 18),
|
totalSupply: ethers.formatUnits(totalSupply, 18),
|
||||||
deployerBalance: ethers.formatUnits(deployerBalance, 18),
|
partnerBalances: partnerBalances, // Информация о партнерах и их балансах
|
||||||
|
logoURI: logoURI, // URL логотипа токена
|
||||||
quorumPercentage: Number(quorumPercentage),
|
quorumPercentage: Number(quorumPercentage),
|
||||||
currentChainId: Number(currentChainId),
|
currentChainId: Number(currentChainId),
|
||||||
participantCount: participantCount
|
participantCount: participantCount
|
||||||
|
|||||||
@@ -66,6 +66,37 @@ router.post('/is-module-active', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Получить информацию о задеплоенных модулях для DLE
|
||||||
|
router.get('/deployed/:dleAddress', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { dleAddress } = req.params;
|
||||||
|
|
||||||
|
if (!dleAddress) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
error: 'Адрес DLE обязателен'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`[DLE Modules] Получение информации о модулях для DLE: ${dleAddress}`);
|
||||||
|
|
||||||
|
// Получаем информацию о модулях из файлов деплоя
|
||||||
|
const modulesInfo = await getDeployedModulesInfo(dleAddress);
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
data: modulesInfo
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[DLE Modules] Ошибка при получении информации о модулях:', error);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: 'Ошибка при получении информации о модулях: ' + error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Получить адрес модуля
|
// Получить адрес модуля
|
||||||
router.post('/get-module-address', async (req, res) => {
|
router.post('/get-module-address', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
@@ -300,4 +331,45 @@ router.post('/create-remove-module-proposal', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Функция для получения информации о задеплоенных модулях
|
||||||
|
async function getDeployedModulesInfo(dleAddress) {
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Ищем файл модулей для конкретного DLE
|
||||||
|
const deployDir = path.join(__dirname, '../temp');
|
||||||
|
if (!fs.existsSync(deployDir)) {
|
||||||
|
return { modules: [], verification: {} };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ищем файл по адресу DLE
|
||||||
|
const modulesFileName = `modules-${dleAddress.toLowerCase()}.json`;
|
||||||
|
const modulesFilePath = path.join(deployDir, modulesFileName);
|
||||||
|
|
||||||
|
if (!fs.existsSync(modulesFilePath)) {
|
||||||
|
console.log(`[DLE Modules] Файл модулей не найден: ${modulesFileName}`);
|
||||||
|
return { modules: [], verification: {} };
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(fs.readFileSync(modulesFilePath, 'utf8'));
|
||||||
|
console.log(`[DLE Modules] Загружена информация о модулях для DLE: ${dleAddress}`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
modules: data.modules || [],
|
||||||
|
verification: data.verification || {},
|
||||||
|
deployTimestamp: data.deployTimestamp
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Ошибка при чтении файла ${modulesFileName}:`, error);
|
||||||
|
return { modules: [], verification: {} };
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Ошибка при получении информации о модулях:', error);
|
||||||
|
return { modules: [], verification: {} };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@@ -173,6 +173,230 @@ async function deployInNetwork(rpcUrl, pk, salt, initCodeHash, targetDLENonce, d
|
|||||||
return { address: deployedAddress, chainId: Number(net.chainId) };
|
return { address: deployedAddress, chainId: Number(net.chainId) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Деплой модулей в одной сети
|
||||||
|
async function deployModulesInNetwork(rpcUrl, pk, dleAddress) {
|
||||||
|
const { ethers } = hre;
|
||||||
|
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||||
|
const wallet = new ethers.Wallet(pk, provider);
|
||||||
|
const net = await provider.getNetwork();
|
||||||
|
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} deploying modules...`);
|
||||||
|
|
||||||
|
const modules = {};
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Деплой TreasuryModule
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} deploying TreasuryModule...`);
|
||||||
|
const TreasuryModule = await hre.ethers.getContractFactory('TreasuryModule');
|
||||||
|
const treasuryModule = await TreasuryModule.connect(wallet).deploy(
|
||||||
|
dleAddress, // _dleContract
|
||||||
|
Number(net.chainId), // _chainId
|
||||||
|
wallet.address // _emergencyAdmin
|
||||||
|
);
|
||||||
|
await treasuryModule.waitForDeployment();
|
||||||
|
const treasuryAddress = await treasuryModule.getAddress();
|
||||||
|
modules.treasuryModule = treasuryAddress;
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} TreasuryModule deployed at: ${treasuryAddress}`);
|
||||||
|
|
||||||
|
// Деплой TimelockModule
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} deploying TimelockModule...`);
|
||||||
|
const TimelockModule = await hre.ethers.getContractFactory('TimelockModule');
|
||||||
|
const timelockModule = await TimelockModule.connect(wallet).deploy(
|
||||||
|
dleAddress // _dleContract
|
||||||
|
);
|
||||||
|
await timelockModule.waitForDeployment();
|
||||||
|
const timelockAddress = await timelockModule.getAddress();
|
||||||
|
modules.timelockModule = timelockAddress;
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} TimelockModule deployed at: ${timelockAddress}`);
|
||||||
|
|
||||||
|
// Деплой DLEReader
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} deploying DLEReader...`);
|
||||||
|
const DLEReader = await hre.ethers.getContractFactory('DLEReader');
|
||||||
|
const dleReader = await DLEReader.connect(wallet).deploy(
|
||||||
|
dleAddress // _dleContract
|
||||||
|
);
|
||||||
|
await dleReader.waitForDeployment();
|
||||||
|
const readerAddress = await dleReader.getAddress();
|
||||||
|
modules.dleReader = readerAddress;
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} DLEReader deployed at: ${readerAddress}`);
|
||||||
|
|
||||||
|
// Инициализация модулей в DLE
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} initializing modules in DLE...`);
|
||||||
|
const dleContract = await hre.ethers.getContractAt('DLE', dleAddress, wallet);
|
||||||
|
|
||||||
|
// Инициализация базовых модулей
|
||||||
|
await dleContract.initializeBaseModules(treasuryAddress, timelockAddress, readerAddress);
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} base modules initialized`);
|
||||||
|
|
||||||
|
// Инициализация logoURI
|
||||||
|
try {
|
||||||
|
// Используем логотип из параметров деплоя или fallback
|
||||||
|
const logoURL = params.logoURI || "https://via.placeholder.com/200x200/0066cc/ffffff?text=DLE";
|
||||||
|
await dleContract.initializeLogoURI(logoURL);
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} logoURI initialized: ${logoURL}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} logoURI initialization failed: ${e.message}`);
|
||||||
|
// Fallback на базовый логотип
|
||||||
|
try {
|
||||||
|
await dleContract.initializeLogoURI("https://via.placeholder.com/200x200/0066cc/ffffff?text=DLE");
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} fallback logoURI initialized`);
|
||||||
|
} catch (fallbackError) {
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} fallback logoURI also failed: ${fallbackError.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[MULTI_DBG] chainId=${Number(net.chainId)} module deployment failed:`, error.message);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Деплой модулей во всех сетях
|
||||||
|
async function deployModulesInAllNetworks(networks, pk, dleAddress) {
|
||||||
|
const moduleResults = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < networks.length; i++) {
|
||||||
|
const rpcUrl = networks[i];
|
||||||
|
console.log(`[MULTI_DBG] deploying modules to network ${i + 1}/${networks.length}: ${rpcUrl}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const modules = await deployModulesInNetwork(rpcUrl, pk, dleAddress);
|
||||||
|
moduleResults.push(modules);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[MULTI_DBG] Failed to deploy modules in network ${i + 1}:`, error.message);
|
||||||
|
moduleResults.push({ error: error.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return moduleResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Верификация контрактов в одной сети
|
||||||
|
async function verifyContractsInNetwork(rpcUrl, pk, dleAddress, modules, params) {
|
||||||
|
const { ethers } = hre;
|
||||||
|
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||||
|
const wallet = new ethers.Wallet(pk, provider);
|
||||||
|
const net = await provider.getNetwork();
|
||||||
|
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} starting verification...`);
|
||||||
|
|
||||||
|
const verification = {};
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Верификация DLE
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} verifying DLE...`);
|
||||||
|
await hre.run("verify:verify", {
|
||||||
|
address: dleAddress,
|
||||||
|
constructorArguments: [
|
||||||
|
{
|
||||||
|
name: params.name || '',
|
||||||
|
symbol: params.symbol || '',
|
||||||
|
location: params.location || '',
|
||||||
|
coordinates: params.coordinates || '',
|
||||||
|
jurisdiction: params.jurisdiction || 0,
|
||||||
|
oktmo: params.oktmo || '',
|
||||||
|
okvedCodes: params.okvedCodes || [],
|
||||||
|
kpp: params.kpp ? BigInt(params.kpp) : 0n,
|
||||||
|
quorumPercentage: params.quorumPercentage || 51,
|
||||||
|
initialPartners: params.initialPartners || [],
|
||||||
|
initialAmounts: (params.initialAmounts || []).map(amount => BigInt(amount)),
|
||||||
|
supportedChainIds: (params.supportedChainIds || []).map(id => BigInt(id))
|
||||||
|
},
|
||||||
|
BigInt(params.currentChainId || params.supportedChainIds?.[0] || 1),
|
||||||
|
params.initializer || params.initialPartners?.[0] || "0x0000000000000000000000000000000000000000"
|
||||||
|
],
|
||||||
|
});
|
||||||
|
verification.dle = 'success';
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} DLE verification successful`);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} DLE verification failed: ${error.message}`);
|
||||||
|
verification.dle = 'failed';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Верификация модулей
|
||||||
|
if (modules && !modules.error) {
|
||||||
|
try {
|
||||||
|
// Верификация TreasuryModule
|
||||||
|
if (modules.treasuryModule) {
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} verifying TreasuryModule...`);
|
||||||
|
await hre.run("verify:verify", {
|
||||||
|
address: modules.treasuryModule,
|
||||||
|
constructorArguments: [
|
||||||
|
dleAddress, // _dleContract
|
||||||
|
Number(net.chainId), // _chainId
|
||||||
|
wallet.address // _emergencyAdmin
|
||||||
|
],
|
||||||
|
});
|
||||||
|
verification.treasuryModule = 'success';
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} TreasuryModule verification successful`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} TreasuryModule verification failed: ${error.message}`);
|
||||||
|
verification.treasuryModule = 'failed';
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Верификация TimelockModule
|
||||||
|
if (modules.timelockModule) {
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} verifying TimelockModule...`);
|
||||||
|
await hre.run("verify:verify", {
|
||||||
|
address: modules.timelockModule,
|
||||||
|
constructorArguments: [
|
||||||
|
dleAddress // _dleContract
|
||||||
|
],
|
||||||
|
});
|
||||||
|
verification.timelockModule = 'success';
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} TimelockModule verification successful`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} TimelockModule verification failed: ${error.message}`);
|
||||||
|
verification.timelockModule = 'failed';
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Верификация DLEReader
|
||||||
|
if (modules.dleReader) {
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} verifying DLEReader...`);
|
||||||
|
await hre.run("verify:verify", {
|
||||||
|
address: modules.dleReader,
|
||||||
|
constructorArguments: [
|
||||||
|
dleAddress // _dleContract
|
||||||
|
],
|
||||||
|
});
|
||||||
|
verification.dleReader = 'success';
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} DLEReader verification successful`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`[MULTI_DBG] chainId=${Number(net.chainId)} DLEReader verification failed: ${error.message}`);
|
||||||
|
verification.dleReader = 'failed';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return verification;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Верификация контрактов во всех сетях
|
||||||
|
async function verifyContractsInAllNetworks(networks, pk, dleAddress, moduleResults, params) {
|
||||||
|
const verificationResults = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < networks.length; i++) {
|
||||||
|
const rpcUrl = networks[i];
|
||||||
|
console.log(`[MULTI_DBG] verifying contracts in network ${i + 1}/${networks.length}: ${rpcUrl}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const verification = await verifyContractsInNetwork(rpcUrl, pk, dleAddress, moduleResults[i], params);
|
||||||
|
verificationResults.push(verification);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[MULTI_DBG] Failed to verify contracts in network ${i + 1}:`, error.message);
|
||||||
|
verificationResults.push({ error: error.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return verificationResults;
|
||||||
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const { ethers } = hre;
|
const { ethers } = hre;
|
||||||
|
|
||||||
@@ -258,7 +482,41 @@ async function main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log('[MULTI_DBG] SUCCESS: All DLE addresses are identical:', uniqueAddresses[0]);
|
console.log('[MULTI_DBG] SUCCESS: All DLE addresses are identical:', uniqueAddresses[0]);
|
||||||
console.log('MULTICHAIN_DEPLOY_RESULT', JSON.stringify(results));
|
|
||||||
|
// Деплой модулей во всех сетях
|
||||||
|
console.log('[MULTI_DBG] Starting module deployment...');
|
||||||
|
const moduleResults = await deployModulesInAllNetworks(networks, pk, uniqueAddresses[0]);
|
||||||
|
|
||||||
|
// Верификация контрактов
|
||||||
|
console.log('[MULTI_DBG] Starting contract verification...');
|
||||||
|
const verificationResults = await verifyContractsInAllNetworks(networks, pk, uniqueAddresses[0], moduleResults, params);
|
||||||
|
|
||||||
|
// Объединяем результаты
|
||||||
|
const finalResults = results.map((result, index) => ({
|
||||||
|
...result,
|
||||||
|
modules: moduleResults[index] || {},
|
||||||
|
verification: verificationResults[index] || {}
|
||||||
|
}));
|
||||||
|
|
||||||
|
console.log('MULTICHAIN_DEPLOY_RESULT', JSON.stringify(finalResults));
|
||||||
|
|
||||||
|
// Сохраняем информацию о модулях в отдельный файл для каждого DLE
|
||||||
|
const modulesInfo = {
|
||||||
|
dleAddress: uniqueAddresses[0],
|
||||||
|
modules: moduleResults,
|
||||||
|
verification: verificationResults,
|
||||||
|
deployTimestamp: new Date().toISOString()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Создаем директорию temp если её нет
|
||||||
|
const tempDir = path.join(__dirname, '../temp');
|
||||||
|
if (!fs.existsSync(tempDir)) {
|
||||||
|
fs.mkdirSync(tempDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const deployResultPath = path.join(tempDir, `modules-${uniqueAddresses[0].toLowerCase()}.json`);
|
||||||
|
fs.writeFileSync(deployResultPath, JSON.stringify(modulesInfo, null, 2));
|
||||||
|
console.log(`[MULTI_DBG] Modules info saved to: ${deployResultPath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((e) => { console.error(e); process.exit(1); });
|
main().catch((e) => { console.error(e); process.exit(1); });
|
||||||
|
|||||||
@@ -458,6 +458,18 @@ class DLEV2Service {
|
|||||||
deployParams.currentChainId = 1; // По умолчанию Ethereum
|
deployParams.currentChainId = 1; // По умолчанию Ethereum
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Обрабатываем logoURI
|
||||||
|
if (deployParams.logoURI) {
|
||||||
|
// Если logoURI относительный путь, делаем его абсолютным
|
||||||
|
if (deployParams.logoURI.startsWith('/uploads/')) {
|
||||||
|
deployParams.logoURI = `http://localhost:3000${deployParams.logoURI}`;
|
||||||
|
}
|
||||||
|
// Если это placeholder, оставляем как есть
|
||||||
|
if (deployParams.logoURI.includes('placeholder.com')) {
|
||||||
|
// Оставляем как есть
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return deployParams;
|
return deployParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,8 +585,24 @@ class DLEV2Service {
|
|||||||
const resultMatch = stdout.match(/MULTICHAIN_DEPLOY_RESULT\s+(\[.*\])/);
|
const resultMatch = stdout.match(/MULTICHAIN_DEPLOY_RESULT\s+(\[.*\])/);
|
||||||
|
|
||||||
if (resultMatch) {
|
if (resultMatch) {
|
||||||
const result = JSON.parse(resultMatch[1]);
|
const deployResults = JSON.parse(resultMatch[1]);
|
||||||
resolve(result);
|
|
||||||
|
// Преобразуем результат в нужный формат
|
||||||
|
const addresses = deployResults.map(r => r.address);
|
||||||
|
const allSame = addresses.every(addr => addr.toLowerCase() === addresses[0].toLowerCase());
|
||||||
|
|
||||||
|
resolve({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
dleAddress: addresses[0],
|
||||||
|
networks: deployResults.map((r, index) => ({
|
||||||
|
chainId: r.chainId,
|
||||||
|
address: r.address,
|
||||||
|
success: true
|
||||||
|
})),
|
||||||
|
allSame
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
// Fallback: ищем адреса DLE в выводе по новому формату
|
// Fallback: ищем адреса DLE в выводе по новому формату
|
||||||
const dleAddressMatches = stdout.match(/\[MULTI_DBG\] chainId=\d+ DLE deployed at=(0x[a-fA-F0-9]{40})/g);
|
const dleAddressMatches = stdout.match(/\[MULTI_DBG\] chainId=\d+ DLE deployed at=(0x[a-fA-F0-9]{40})/g);
|
||||||
|
|||||||
3
frontend/public/dle-logo.png
Normal file
3
frontend/public/dle-logo.png
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Это placeholder для логотипа DLE
|
||||||
|
# В реальном проекте здесь должен быть PNG файл с логотипом
|
||||||
|
# Размер рекомендуется: 200x200 пикселей
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 9.4 KiB |
20
frontend/public/uploads/logos/default-token.svg
Normal file
20
frontend/public/uploads/logos/default-token.svg
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||||
|
<stop offset="0%" style="stop-color:#0066cc;stop-opacity:1" />
|
||||||
|
<stop offset="100%" style="stop-color:#0056b3;stop-opacity:1" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<!-- Фон -->
|
||||||
|
<rect width="200" height="200" rx="20" fill="url(#grad1)"/>
|
||||||
|
|
||||||
|
<!-- Текст DLE -->
|
||||||
|
<text x="100" y="120" font-family="Arial, sans-serif" font-size="48" font-weight="bold" text-anchor="middle" fill="white">DLE</text>
|
||||||
|
|
||||||
|
<!-- Дополнительные элементы -->
|
||||||
|
<circle cx="50" cy="50" r="8" fill="rgba(255,255,255,0.3)"/>
|
||||||
|
<circle cx="150" cy="50" r="8" fill="rgba(255,255,255,0.3)"/>
|
||||||
|
<circle cx="50" cy="150" r="8" fill="rgba(255,255,255,0.3)"/>
|
||||||
|
<circle cx="150" cy="150" r="8" fill="rgba(255,255,255,0.3)"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 907 B |
@@ -58,8 +58,20 @@
|
|||||||
@click="selectDle(dle)"
|
@click="selectDle(dle)"
|
||||||
>
|
>
|
||||||
<div class="dle-header">
|
<div class="dle-header">
|
||||||
<h3>{{ dle.name }} ({{ dle.symbol }})</h3>
|
<div class="dle-title-section">
|
||||||
<span class="dle-version">{{ dle.version || 'v2' }}</span>
|
<img
|
||||||
|
v-if="dle.logoURI"
|
||||||
|
:src="dle.logoURI"
|
||||||
|
:alt="dle.name"
|
||||||
|
class="dle-logo"
|
||||||
|
@error="handleLogoError"
|
||||||
|
/>
|
||||||
|
<div class="default-logo" v-else>DLE</div>
|
||||||
|
<div class="dle-title">
|
||||||
|
<h3>{{ dle.name }} ({{ dle.symbol }})</h3>
|
||||||
|
<span class="dle-version">{{ dle.version || 'v2' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dle-details">
|
<div class="dle-details">
|
||||||
@@ -106,7 +118,22 @@
|
|||||||
<strong>Коды ОКВЭД:</strong> {{ dle.okvedCodes?.join(', ') || 'Не указаны' }}
|
<strong>Коды ОКВЭД:</strong> {{ dle.okvedCodes?.join(', ') || 'Не указаны' }}
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item">
|
||||||
<strong>Партнеры:</strong> {{ dle.participantCount || 0 }} участников
|
<strong>Партнеры:</strong>
|
||||||
|
<span v-if="dle.partnerBalances && dle.partnerBalances.length > 0">
|
||||||
|
{{ dle.participantCount || dle.partnerBalances.length }} участников
|
||||||
|
<div class="partners-details">
|
||||||
|
<div v-for="(partner, index) in dle.partnerBalances.slice(0, 3)" :key="index" class="partner-info">
|
||||||
|
<span class="partner-address">{{ shortenAddress(partner.address) }}</span>
|
||||||
|
<span class="partner-balance">{{ partner.balance }} токенов ({{ partner.percentage.toFixed(1) }}%)</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="dle.partnerBalances.length > 3" class="more-partners">
|
||||||
|
+{{ dle.partnerBalances.length - 3 }} еще
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
{{ dle.participantCount || 0 }} участников
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item">
|
||||||
<strong>Статус:</strong>
|
<strong>Статус:</strong>
|
||||||
@@ -229,6 +256,16 @@ const openProposals = () => {
|
|||||||
router.push('/management/proposals');
|
router.push('/management/proposals');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Обработка ошибки загрузки логотипа
|
||||||
|
const handleLogoError = (event) => {
|
||||||
|
console.log('Ошибка загрузки логотипа:', event.target.src);
|
||||||
|
event.target.style.display = 'none';
|
||||||
|
const defaultLogo = event.target.parentElement.querySelector('.default-logo');
|
||||||
|
if (defaultLogo) {
|
||||||
|
defaultLogo.style.display = 'flex';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const openTokens = () => {
|
const openTokens = () => {
|
||||||
router.push('/management/tokens');
|
router.push('/management/tokens');
|
||||||
};
|
};
|
||||||
@@ -309,7 +346,8 @@ async function loadDeployedDles() {
|
|||||||
kpp: blockchainData.kpp || dle.kpp,
|
kpp: blockchainData.kpp || dle.kpp,
|
||||||
// Информация о токенах из блокчейна
|
// Информация о токенах из блокчейна
|
||||||
totalSupply: blockchainData.totalSupply,
|
totalSupply: blockchainData.totalSupply,
|
||||||
deployerBalance: blockchainData.deployerBalance,
|
partnerBalances: blockchainData.partnerBalances || [], // Информация о партнерах
|
||||||
|
logoURI: blockchainData.logoURI || '', // URL логотипа
|
||||||
// Количество участников (держателей токенов)
|
// Количество участников (держателей токенов)
|
||||||
participantCount: blockchainData.participantCount || 0
|
participantCount: blockchainData.participantCount || 0
|
||||||
};
|
};
|
||||||
@@ -867,6 +905,97 @@ onBeforeUnmount(() => {
|
|||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Стили для отображения логотипа */
|
||||||
|
.dle-title-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dle-logo {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 8px;
|
||||||
|
object-fit: contain;
|
||||||
|
border: 2px solid #e9ecef;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.default-logo {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: linear-gradient(135deg, var(--color-primary), #0056b3);
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 14px;
|
||||||
|
border: 2px solid #e9ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dle-title {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dle-title h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dle-version {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #6c757d;
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
align-self: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Стили для отображения партнеров */
|
||||||
|
.partners-details {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-radius: 6px;
|
||||||
|
border-left: 3px solid var(--color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.partner-info {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.25rem 0;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.partner-info:not(:last-child) {
|
||||||
|
border-bottom: 1px solid #e9ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.partner-address {
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
color: #495057;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.partner-balance {
|
||||||
|
color: var(--color-primary);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.more-partners {
|
||||||
|
text-align: center;
|
||||||
|
color: #6c757d;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
padding: 0.25rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Адаптивность */
|
/* Адаптивность */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.blocks-row {
|
.blocks-row {
|
||||||
@@ -880,6 +1009,25 @@ onBeforeUnmount(() => {
|
|||||||
.management-block h3 {
|
.management-block h3 {
|
||||||
font-size: 1.3rem;
|
font-size: 1.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.partner-info {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dle-title-section {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dle-logo,
|
||||||
|
.default-logo {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2475,6 +2475,28 @@ const deploySmartContracts = async () => {
|
|||||||
autoVerifyAfterDeploy: autoVerifyAfterDeploy.value
|
autoVerifyAfterDeploy: autoVerifyAfterDeploy.value
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Обработка логотипа
|
||||||
|
try {
|
||||||
|
if (logoFile.value) {
|
||||||
|
const form = new FormData();
|
||||||
|
form.append('logo', logoFile.value);
|
||||||
|
const uploadResp = await axios.post('/uploads/logo', form, { headers: { 'Content-Type': 'multipart/form-data' } });
|
||||||
|
const uploaded = uploadResp.data?.data?.url || uploadResp.data?.data?.path;
|
||||||
|
if (uploaded) {
|
||||||
|
deployData.logoURI = uploaded;
|
||||||
|
}
|
||||||
|
} else if (ensResolvedUrl.value) {
|
||||||
|
deployData.logoURI = ensResolvedUrl.value;
|
||||||
|
} else {
|
||||||
|
// фолбэк на дефолт
|
||||||
|
deployData.logoURI = '/uploads/logos/default-token.svg';
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Ошибка при обработке логотипа:', error.message);
|
||||||
|
// Используем fallback логотип
|
||||||
|
deployData.logoURI = '/uploads/logos/default-token.svg';
|
||||||
|
}
|
||||||
|
|
||||||
console.log('Данные для деплоя DLE:', deployData);
|
console.log('Данные для деплоя DLE:', deployData);
|
||||||
|
|
||||||
// Предварительная проверка балансов во всех сетях
|
// Предварительная проверка балансов во всех сетях
|
||||||
|
|||||||
Reference in New Issue
Block a user