ваше сообщение коммита
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../build-info/ca6cf114dd2b9a54ebfddbb4ba9a86a9.json"
|
||||
"buildInfo": "../../../../build-info/5f658ec7c83a39083e0b58539865c835.json"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../build-info/ca6cf114dd2b9a54ebfddbb4ba9a86a9.json"
|
||||
"buildInfo": "../../../../build-info/5f658ec7c83a39083e0b58539865c835.json"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../build-info/ca6cf114dd2b9a54ebfddbb4ba9a86a9.json"
|
||||
"buildInfo": "../../../../build-info/5f658ec7c83a39083e0b58539865c835.json"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../../build-info/ca6cf114dd2b9a54ebfddbb4ba9a86a9.json"
|
||||
"buildInfo": "../../../../../build-info/5f658ec7c83a39083e0b58539865c835.json"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../../build-info/ca6cf114dd2b9a54ebfddbb4ba9a86a9.json"
|
||||
"buildInfo": "../../../../../build-info/5f658ec7c83a39083e0b58539865c835.json"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../../../../../build-info/ca6cf114dd2b9a54ebfddbb4ba9a86a9.json"
|
||||
"buildInfo": "../../../../../../build-info/5f658ec7c83a39083e0b58539865c835.json"
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"_format": "hh-sol-dbg-1",
|
||||
"buildInfo": "../../build-info/ca6cf114dd2b9a54ebfddbb4ba9a86a9.json"
|
||||
"buildInfo": "../../build-info/5f658ec7c83a39083e0b58539865c835.json"
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
22
backend/cache/solidity-files-cache.json
vendored
22
backend/cache/solidity-files-cache.json
vendored
@@ -42,8 +42,8 @@
|
||||
]
|
||||
},
|
||||
"/home/alex/Digital_Legal_Entity(DLE)/backend/node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol": {
|
||||
"lastModificationDate": 1751738715692,
|
||||
"contentHash": "227a6eb2225701c12d9c959b758b6333",
|
||||
"lastModificationDate": 1753876422727,
|
||||
"contentHash": "59dfce11284f2636db261df9b6a18f81",
|
||||
"sourceName": "@openzeppelin/contracts/token/ERC20/ERC20.sol",
|
||||
"solcConfig": {
|
||||
"version": "0.8.20",
|
||||
@@ -158,8 +158,8 @@
|
||||
]
|
||||
},
|
||||
"/home/alex/Digital_Legal_Entity(DLE)/backend/node_modules/@openzeppelin/contracts/interfaces/draft-IERC6093.sol": {
|
||||
"lastModificationDate": 1751738715692,
|
||||
"contentHash": "267d92fe4de67b1bdb3302c08f387dbf",
|
||||
"lastModificationDate": 1753876422645,
|
||||
"contentHash": "5041977bbe908de2e6ed0270447f79ad",
|
||||
"sourceName": "@openzeppelin/contracts/interfaces/draft-IERC6093.sol",
|
||||
"solcConfig": {
|
||||
"version": "0.8.20",
|
||||
@@ -188,7 +188,7 @@
|
||||
},
|
||||
"imports": [],
|
||||
"versionPragmas": [
|
||||
"^0.8.20"
|
||||
">=0.8.4"
|
||||
],
|
||||
"artifacts": [
|
||||
"IERC1155Errors",
|
||||
@@ -197,8 +197,8 @@
|
||||
]
|
||||
},
|
||||
"/home/alex/Digital_Legal_Entity(DLE)/backend/node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
|
||||
"lastModificationDate": 1751738715692,
|
||||
"contentHash": "794db3115001aa372c79326fcfd44b1f",
|
||||
"lastModificationDate": 1753876422727,
|
||||
"contentHash": "513778b30d2750f5d2b9b19bbcf748a5",
|
||||
"sourceName": "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol",
|
||||
"solcConfig": {
|
||||
"version": "0.8.20",
|
||||
@@ -229,15 +229,15 @@
|
||||
"../IERC20.sol"
|
||||
],
|
||||
"versionPragmas": [
|
||||
"^0.8.20"
|
||||
">=0.6.2"
|
||||
],
|
||||
"artifacts": [
|
||||
"IERC20Metadata"
|
||||
]
|
||||
},
|
||||
"/home/alex/Digital_Legal_Entity(DLE)/backend/node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol": {
|
||||
"lastModificationDate": 1751738715692,
|
||||
"contentHash": "8f19f64d2adadf448840908bbaf431c8",
|
||||
"lastModificationDate": 1753876422727,
|
||||
"contentHash": "9261adf6457863de3e9892f51317ec89",
|
||||
"sourceName": "@openzeppelin/contracts/token/ERC20/IERC20.sol",
|
||||
"solcConfig": {
|
||||
"version": "0.8.20",
|
||||
@@ -266,7 +266,7 @@
|
||||
},
|
||||
"imports": [],
|
||||
"versionPragmas": [
|
||||
"^0.8.20"
|
||||
">=0.4.16"
|
||||
],
|
||||
"artifacts": [
|
||||
"IERC20"
|
||||
|
||||
@@ -17,6 +17,7 @@ const logger = require('../utils/logger');
|
||||
const auth = require('../middleware/auth');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const ethers = require('ethers'); // Added ethers for private key validation
|
||||
|
||||
/**
|
||||
* @route POST /api/dle-v2
|
||||
@@ -28,8 +29,8 @@ router.post('/', auth.requireAuth, auth.requireAdmin, async (req, res, next) =>
|
||||
const dleParams = req.body;
|
||||
logger.info('Получен запрос на создание DLE v2:', dleParams);
|
||||
|
||||
// Если параметр partners не был передан явно, используем адрес авторизованного пользователя
|
||||
if (!dleParams.partners || dleParams.partners.length === 0) {
|
||||
// Если параметр initialPartners не был передан явно, используем адрес авторизованного пользователя
|
||||
if (!dleParams.initialPartners || dleParams.initialPartners.length === 0) {
|
||||
// Проверяем, есть ли в сессии адрес кошелька пользователя
|
||||
if (!req.user || !req.user.walletAddress) {
|
||||
return res.status(400).json({
|
||||
@@ -39,11 +40,11 @@ router.post('/', auth.requireAuth, auth.requireAdmin, async (req, res, next) =>
|
||||
}
|
||||
|
||||
// Используем адрес авторизованного пользователя
|
||||
dleParams.partners = [req.user.address || req.user.walletAddress];
|
||||
dleParams.initialPartners = [req.user.address || req.user.walletAddress];
|
||||
|
||||
// Если суммы не указаны, используем значение по умолчанию (100% токенов)
|
||||
if (!dleParams.amounts || dleParams.amounts.length === 0) {
|
||||
dleParams.amounts = ['1000000'];
|
||||
if (!dleParams.initialAmounts || dleParams.initialAmounts.length === 0) {
|
||||
dleParams.initialAmounts = ['1000000000000000000000000']; // 1,000,000 токенов
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,23 +92,40 @@ router.get('/', auth.requireAuth, async (req, res, next) => {
|
||||
});
|
||||
|
||||
/**
|
||||
* @route GET /api/dle-v2/defaults
|
||||
* @desc Получить настройки по умолчанию для DLE v2
|
||||
* @access Private (только для авторизованных пользователей)
|
||||
* @route GET /api/dle-v2/default-params
|
||||
* @desc Получить параметры по умолчанию для создания DLE v2
|
||||
* @access Private
|
||||
*/
|
||||
router.get('/defaults', auth.requireAuth, async (req, res, next) => {
|
||||
// Возвращаем настройки по умолчанию, которые будут использоваться
|
||||
// при заполнении формы на фронтенде
|
||||
router.get('/default-params', auth.requireAuth, async (req, res, next) => {
|
||||
try {
|
||||
const defaultParams = {
|
||||
name: '',
|
||||
symbol: '',
|
||||
location: '',
|
||||
coordinates: '',
|
||||
jurisdiction: 1,
|
||||
oktmo: 45000000000,
|
||||
okvedCodes: [],
|
||||
kpp: 770101001,
|
||||
quorumPercentage: 51,
|
||||
initialPartners: [],
|
||||
initialAmounts: [],
|
||||
supportedChainIds: [1, 137, 56, 42161],
|
||||
currentChainId: 1
|
||||
};
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
votingDelay: 1, // 1 блок задержки перед началом голосования
|
||||
votingPeriod: 45818, // ~1 неделя в блоках (при 13 секундах на блок)
|
||||
proposalThreshold: '100000', // 100,000 токенов
|
||||
quorumPercentage: 4, // 4% от общего количества токенов
|
||||
minTimelockDelay: 2 // 2 дня
|
||||
}
|
||||
data: defaultParams
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Ошибка при получении параметров по умолчанию:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: error.message || 'Произошла ошибка при получении параметров по умолчанию'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -170,4 +188,74 @@ router.delete('/:dleAddress', auth.requireAuth, auth.requireAdmin, async (req, r
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @route POST /api/dle-v2/validate-private-key
|
||||
* @desc Валидировать приватный ключ и получить адрес кошелька
|
||||
* @access Private
|
||||
*/
|
||||
router.post('/validate-private-key', auth.requireAuth, async (req, res, next) => {
|
||||
try {
|
||||
const { privateKey } = req.body;
|
||||
|
||||
if (!privateKey) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Приватный ключ не передан'
|
||||
});
|
||||
}
|
||||
|
||||
// Логируем входящий ключ (только для отладки)
|
||||
logger.info('Получен приватный ключ для валидации:', privateKey);
|
||||
logger.info('Длина входящего ключа:', privateKey.length);
|
||||
|
||||
try {
|
||||
// Очищаем ключ от префикса 0x если есть
|
||||
const cleanKey = privateKey.startsWith('0x') ? privateKey.slice(2) : privateKey;
|
||||
|
||||
// Логируем очищенный ключ (только для отладки)
|
||||
logger.info('Очищенный ключ:', cleanKey);
|
||||
logger.info('Длина очищенного ключа:', cleanKey.length);
|
||||
|
||||
// Проверяем длину и формат (64 символа в hex)
|
||||
if (cleanKey.length !== 64 || !/^[a-fA-F0-9]+$/.test(cleanKey)) {
|
||||
logger.error('Некорректный формат ключа. Длина:', cleanKey.length, 'Формат:', /^[a-fA-F0-9]+$/.test(cleanKey));
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Некорректный формат приватного ключа'
|
||||
});
|
||||
}
|
||||
|
||||
// Генерируем адрес из приватного ключа
|
||||
const wallet = new ethers.Wallet('0x' + cleanKey);
|
||||
const address = wallet.address;
|
||||
|
||||
// Логируем сгенерированный адрес
|
||||
logger.info('Сгенерированный адрес из приватного ключа:', address);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
isValid: true,
|
||||
address: address,
|
||||
error: null
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Ошибка при генерации адреса из приватного ключа:', error);
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
message: 'Некорректный приватный ключ'
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Ошибка при валидации приватного ключа:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: error.message || 'Произошла ошибка при валидации приватного ключа'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -213,7 +213,7 @@ router.get('/', requireAuth, async (req, res, next) => {
|
||||
// --- Формируем ответ ---
|
||||
const contacts = users.map(u => ({
|
||||
id: u.id,
|
||||
name: [u.first_name, u.last_name].filter(Boolean).join(' ') || null,
|
||||
name: null, // Имена теперь только в зашифрованных колонках
|
||||
email: u.email || null,
|
||||
telegram: u.telegram || null,
|
||||
wallet: u.wallet || null,
|
||||
@@ -418,22 +418,37 @@ router.get('/:id', async (req, res, next) => {
|
||||
}
|
||||
|
||||
try {
|
||||
// Получаем ключ шифрования
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
let encryptionKey = 'default-key';
|
||||
|
||||
try {
|
||||
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
|
||||
if (fs.existsSync(keyPath)) {
|
||||
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
|
||||
}
|
||||
} catch (keyError) {
|
||||
console.error('Error reading encryption key:', keyError);
|
||||
}
|
||||
|
||||
const query = db.getQuery();
|
||||
// Получаем пользователя
|
||||
const userResult = await query('SELECT id, decrypt_text(first_name_encrypted, $2) as first_name, decrypt_text(last_name_encrypted, $2) as last_name, created_at, preferred_language, is_blocked FROM users WHERE id = $1', [userId, encryptionKey]);
|
||||
const userResult = await query('SELECT id, created_at, preferred_language, is_blocked FROM users WHERE id = $1', [userId]);
|
||||
if (userResult.rows.length === 0) {
|
||||
return res.status(404).json({ error: 'User not found' });
|
||||
}
|
||||
const user = userResult.rows[0];
|
||||
|
||||
// Получаем идентификаторы
|
||||
const identitiesResult = await query('SELECT decrypt_text(provider_encrypted, $2) as provider, decrypt_text(provider_id_encrypted, $2) as provider_id FROM user_identities WHERE user_id = $1', [userId, encryptionKey]);
|
||||
const identitiesResult = await query('SELECT CASE WHEN provider_encrypted IS NULL OR provider_encrypted = \'\' THEN NULL ELSE decrypt_text(provider_encrypted, $2) END as provider, CASE WHEN provider_id_encrypted IS NULL OR provider_id_encrypted = \'\' THEN NULL ELSE decrypt_text(provider_id_encrypted, $2) END as provider_id FROM user_identities WHERE user_id = $1', [userId, encryptionKey]);
|
||||
const identityMap = {};
|
||||
for (const id of identitiesResult.rows) {
|
||||
identityMap[id.provider] = id.provider_id;
|
||||
}
|
||||
res.json({
|
||||
id: user.id,
|
||||
name: [user.first_name, user.last_name].filter(Boolean).join(' ') || null,
|
||||
name: null, // Пока не используем имена
|
||||
email: identityMap.email || null,
|
||||
telegram: identityMap.telegram || null,
|
||||
wallet: identityMap.wallet || null,
|
||||
@@ -545,9 +560,9 @@ router.post('/import', requireAuth, async (req, res) => {
|
||||
].filter(Boolean);
|
||||
for (const idn of identities) {
|
||||
// Проверяем, есть ли уже такой идентификатор у пользователя
|
||||
const exists = await dbq('SELECT 1 FROM user_identities WHERE user_id = $1 AND provider = $2 AND provider_id = $3', [userId, idn.provider, idn.provider_id]);
|
||||
const exists = await dbq('SELECT 1 FROM user_identities WHERE user_id = $1 AND provider_encrypted = encrypt_text($2, $4) AND provider_id_encrypted = encrypt_text($3, $4)', [userId, idn.provider, idn.provider_id, encryptionKey]);
|
||||
if (!exists.rows.length) {
|
||||
await dbq('INSERT INTO user_identities (user_id, provider, provider_id) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING', [userId, idn.provider, idn.provider_id]);
|
||||
await dbq('INSERT INTO user_identities (user_id, provider_encrypted, provider_id_encrypted) VALUES ($1, encrypt_text($2, $4), encrypt_text($3, $4)) ON CONFLICT DO NOTHING', [userId, idn.provider, idn.provider_id, encryptionKey]);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -34,70 +34,59 @@ async function main() {
|
||||
|
||||
const DLE = await ethers.getContractFactory("DLE");
|
||||
|
||||
// Преобразуем параметры голосования
|
||||
const votingDelay = deployParams.votingDelay || 1;
|
||||
const votingPeriod = deployParams.votingPeriod || 45818; // ~1 неделя
|
||||
const proposalThreshold = deployParams.proposalThreshold || ethers.parseEther("100000");
|
||||
const quorumPercentage = deployParams.quorumPercentage || 4;
|
||||
const minTimelockDelay = (deployParams.minTimelockDelay || 2) * 24 * 60 * 60; // дни в секунды
|
||||
// Создаем структуру DLEConfig
|
||||
const dleConfig = {
|
||||
name: deployParams.name,
|
||||
symbol: deployParams.symbol,
|
||||
location: deployParams.location,
|
||||
coordinates: deployParams.coordinates || "0,0",
|
||||
jurisdiction: deployParams.jurisdiction || 1,
|
||||
oktmo: deployParams.oktmo || 45000000000,
|
||||
okvedCodes: deployParams.okvedCodes || [],
|
||||
kpp: deployParams.kpp || 770101001,
|
||||
quorumPercentage: deployParams.quorumPercentage || 51,
|
||||
initialPartners: deployParams.initialPartners,
|
||||
initialAmounts: deployParams.initialAmounts,
|
||||
supportedChainIds: deployParams.supportedChainIds || [1, 137, 56, 42161] // Ethereum, Polygon, BSC, Arbitrum
|
||||
};
|
||||
|
||||
const dle = await DLE.deploy(
|
||||
deployParams.name,
|
||||
deployParams.symbol,
|
||||
deployParams.location,
|
||||
deployParams.isicCodes || [],
|
||||
votingDelay,
|
||||
votingPeriod,
|
||||
proposalThreshold,
|
||||
quorumPercentage,
|
||||
minTimelockDelay
|
||||
);
|
||||
const currentChainId = deployParams.currentChainId || 1; // По умолчанию Ethereum
|
||||
|
||||
const dle = await DLE.deploy(dleConfig, currentChainId);
|
||||
|
||||
await dle.waitForDeployment();
|
||||
const dleAddress = await dle.getAddress();
|
||||
console.log(`DLE v2 задеплоен по адресу: ${dleAddress}`);
|
||||
|
||||
// 2. Получаем адрес таймлока
|
||||
const timelockAddress = await dle.getTimelockAddress();
|
||||
console.log(`Таймлок создан по адресу: ${timelockAddress}`);
|
||||
|
||||
// 3. Распределяем начальные токены
|
||||
console.log("\n3. Распределение начальных токенов...");
|
||||
const distributeTx = await dle.distributeInitialTokens(
|
||||
deployParams.partners,
|
||||
deployParams.amounts
|
||||
);
|
||||
await distributeTx.wait();
|
||||
console.log(`Токены распределены между партнерами`);
|
||||
|
||||
// 4. Получаем информацию о DLE
|
||||
// 2. Получаем информацию о DLE
|
||||
const dleInfo = await dle.getDLEInfo();
|
||||
console.log("\n4. Информация о DLE:");
|
||||
console.log("\n2. Информация о DLE:");
|
||||
console.log(`Название: ${dleInfo.name}`);
|
||||
console.log(`Символ: ${dleInfo.symbol}`);
|
||||
console.log(`Местонахождение: ${dleInfo.location}`);
|
||||
console.log(`Коды деятельности: ${dleInfo.isicCodes.join(', ')}`);
|
||||
console.log(`Коды деятельности: ${dleInfo.okvedCodes.join(', ')}`);
|
||||
console.log(`Дата создания: ${new Date(dleInfo.creationTimestamp * 1000).toISOString()}`);
|
||||
|
||||
// 5. Сохраняем информацию о созданном DLE
|
||||
console.log("\n5. Сохранение информации о DLE v2...");
|
||||
// 3. Сохраняем информацию о созданном DLE
|
||||
console.log("\n3. Сохранение информации о DLE v2...");
|
||||
const dleData = {
|
||||
name: deployParams.name,
|
||||
symbol: deployParams.symbol,
|
||||
location: deployParams.location,
|
||||
isicCodes: deployParams.isicCodes || [],
|
||||
coordinates: deployParams.coordinates || "0,0",
|
||||
jurisdiction: deployParams.jurisdiction || 1,
|
||||
oktmo: deployParams.oktmo || 45000000000,
|
||||
okvedCodes: deployParams.isicCodes || [],
|
||||
kpp: deployParams.kpp || 770101001,
|
||||
dleAddress: dleAddress,
|
||||
timelockAddress: timelockAddress,
|
||||
creationBlock: (await distributeTx.provider.getBlockNumber()),
|
||||
creationTimestamp: (await distributeTx.provider.getBlock()).timestamp,
|
||||
creationBlock: (await dle.provider.getBlockNumber()),
|
||||
creationTimestamp: (await dle.provider.getBlock()).timestamp,
|
||||
deployedManually: true,
|
||||
version: "v2",
|
||||
governanceSettings: {
|
||||
votingDelay: votingDelay,
|
||||
votingPeriod: votingPeriod,
|
||||
proposalThreshold: proposalThreshold.toString(),
|
||||
quorumPercentage: quorumPercentage,
|
||||
minTimelockDelay: deployParams.minTimelockDelay || 2
|
||||
quorumPercentage: deployParams.quorumPercentage || 51,
|
||||
supportedChainIds: deployParams.supportedChainIds || [1, 137, 56, 42161],
|
||||
currentChainId: currentChainId
|
||||
}
|
||||
};
|
||||
|
||||
@@ -105,13 +94,11 @@ async function main() {
|
||||
|
||||
console.log("\nDLE v2 успешно создан!");
|
||||
console.log(`Адрес DLE: ${dleAddress}`);
|
||||
console.log(`Адрес таймлока: ${timelockAddress}`);
|
||||
console.log(`Версия: v2 (единый контракт)`);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
dleAddress: dleAddress,
|
||||
timelockAddress: timelockAddress,
|
||||
data: dleData
|
||||
};
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"name": "рога и копыта",
|
||||
"symbol": "roga",
|
||||
"location": "325000, 中国, 瓯海区",
|
||||
"isicCodes": [
|
||||
"9000"
|
||||
],
|
||||
"partners": [
|
||||
"0xf45aa4917b3775ba37f48aeb3dc1a943561e9e0b",
|
||||
"0x15a4ed4759e5762174b300a4cf51cc17ad967f4d"
|
||||
],
|
||||
"amounts": [
|
||||
"1000000000000000000",
|
||||
"10000000000000000000000"
|
||||
],
|
||||
"network": "sepolia",
|
||||
"minTimelockDelay": 5,
|
||||
"votingDelay": 46523,
|
||||
"votingPeriod": 6646,
|
||||
"proposalThreshold": "0",
|
||||
"quorumPercentage": 51,
|
||||
"privateKey": "7de38b2ada1d23581342f106c8587ce26068797b3bc06656e24b9dcd1810c7b1"
|
||||
}
|
||||
@@ -103,10 +103,11 @@ class AuthService {
|
||||
const userId = newUserResult.rows[0].id;
|
||||
|
||||
// Добавляем идентификатор кошелька (всегда в нижнем регистре)
|
||||
await db.getQuery()(
|
||||
'INSERT INTO user_identities (user_id, provider, provider_id) VALUES ($1, $2, $3)',
|
||||
[userId, 'wallet', normalizedAddress]
|
||||
);
|
||||
await encryptedDb.saveData('user_identities', {
|
||||
user_id: userId,
|
||||
provider: 'wallet',
|
||||
provider_id: normalizedAddress
|
||||
});
|
||||
|
||||
// Проверяем, есть ли у пользователя роль админа
|
||||
const isAdmin = await checkAdminRole(normalizedAddress);
|
||||
@@ -400,11 +401,11 @@ class AuthService {
|
||||
// Если в сессии нет авторизованного пользователя, проверяем существующие идентификаторы
|
||||
// Проверяем, существует ли уже пользователь с таким Telegram ID
|
||||
const existingUserResult = await db.getQuery()(
|
||||
`SELECT u.*, ui.provider, ui.provider_id
|
||||
`SELECT u.*, decrypt_text(ui.provider_encrypted, $2) as provider, decrypt_text(ui.provider_id_encrypted, $2) as provider_id
|
||||
FROM users u
|
||||
JOIN user_identities ui ON u.id = ui.user_id
|
||||
WHERE ui.provider = 'telegram' AND ui.provider_id = $1`,
|
||||
[telegramId]
|
||||
WHERE ui.provider_encrypted = encrypt_text('telegram', $2) AND ui.provider_id_encrypted = encrypt_text($1, $2)`,
|
||||
[telegramId, encryptionKey]
|
||||
);
|
||||
|
||||
// Если пользователь существует с таким telegramId, используем его
|
||||
@@ -423,10 +424,11 @@ class AuthService {
|
||||
isNewUser = true;
|
||||
|
||||
// Добавляем Telegram идентификатор
|
||||
await db.getQuery()(
|
||||
'INSERT INTO user_identities (user_id, provider, provider_id) VALUES ($1, $2, $3)',
|
||||
[userId, 'telegram', telegramId]
|
||||
);
|
||||
await encryptedDb.saveData('user_identities', {
|
||||
user_id: userId,
|
||||
provider: 'telegram',
|
||||
provider_id: telegramId
|
||||
});
|
||||
|
||||
logger.info(
|
||||
`[verifyTelegramAuth] Created new user ${userId} for Telegram ID ${telegramId}`
|
||||
@@ -582,10 +584,34 @@ class AuthService {
|
||||
async getUserIdentities(userId) {
|
||||
try {
|
||||
const identities = await encryptedDb.getData('user_identities', { user_id: userId }, null, 'created_at DESC');
|
||||
return identities;
|
||||
|
||||
// Данные уже расшифрованы encryptedDb, просто переименовываем поля
|
||||
const formattedIdentities = identities.map(identity => ({
|
||||
id: identity.id,
|
||||
user_id: identity.user_id,
|
||||
created_at: identity.created_at,
|
||||
provider: identity.provider, // Уже расшифровано
|
||||
provider_id: identity.provider_id // Уже расшифровано
|
||||
}));
|
||||
|
||||
return formattedIdentities;
|
||||
} catch (error) {
|
||||
logger.error('[getUserIdentities] Error:', error);
|
||||
throw error;
|
||||
|
||||
// Если произошла ошибка расшифровки, попробуем получить данные напрямую
|
||||
try {
|
||||
logger.info(`[AuthService] Trying to get unencrypted data for user ${userId}`);
|
||||
const { rows } = await db.getQuery()(
|
||||
'SELECT id, user_id, created_at, provider_encrypted as provider, provider_id_encrypted as provider_id FROM user_identities WHERE user_id = $1 ORDER BY created_at DESC',
|
||||
[userId]
|
||||
);
|
||||
|
||||
logger.info(`[AuthService] Found ${rows.length} unencrypted identities for user ${userId}`);
|
||||
return rows;
|
||||
} catch (fallbackError) {
|
||||
logger.error(`[AuthService] Fallback error getting identities for user ${userId}:`, fallbackError);
|
||||
throw fallbackError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -667,11 +693,11 @@ class AuthService {
|
||||
}
|
||||
|
||||
// Добавляем новый идентификатор для пользователя
|
||||
await db.getQuery()(
|
||||
`INSERT INTO user_identities (user_id, provider, provider_id)
|
||||
VALUES ($1, $2, $3)`,
|
||||
[userId, provider, normalizedProviderId]
|
||||
);
|
||||
await encryptedDb.saveData('user_identities', {
|
||||
user_id: userId,
|
||||
provider: provider,
|
||||
provider_id: normalizedProviderId
|
||||
});
|
||||
|
||||
// Проверяем и обновляем роль администратора, если это идентификатор кошелька
|
||||
let isAdmin = false;
|
||||
|
||||
@@ -15,7 +15,7 @@ const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { ethers } = require('ethers');
|
||||
const logger = require('../utils/logger');
|
||||
const { getRpcUrlByNetworkId } = require('./rpcProviderService');
|
||||
const { getRpcUrlByChainId } = require('./rpcProviderService');
|
||||
|
||||
/**
|
||||
* Сервис для управления DLE v2 (Digital Legal Entity)
|
||||
@@ -49,10 +49,15 @@ class DLEV2Service {
|
||||
fs.copyFileSync(paramsFile, tempParamsFile);
|
||||
logger.info(`Файл параметров скопирован успешно`);
|
||||
|
||||
// Получаем rpc_url из базы по выбранной сети
|
||||
const rpcUrl = await getRpcUrlByNetworkId(deployParams.network);
|
||||
// Определяем сеть для деплоя (берем первую из выбранных сетей)
|
||||
const chainId = deployParams.supportedChainIds && deployParams.supportedChainIds.length > 0
|
||||
? deployParams.supportedChainIds[0]
|
||||
: 1; // По умолчанию Ethereum
|
||||
|
||||
// Получаем rpc_url из базы по chain_id
|
||||
const rpcUrl = await getRpcUrlByChainId(chainId);
|
||||
if (!rpcUrl) {
|
||||
throw new Error(`RPC URL для сети ${deployParams.network} не найден в базе данных`);
|
||||
throw new Error(`RPC URL для сети с chain_id ${chainId} не найден в базе данных`);
|
||||
}
|
||||
if (!dleParams.privateKey) {
|
||||
throw new Error('Приватный ключ для деплоя не передан');
|
||||
@@ -62,8 +67,8 @@ class DLEV2Service {
|
||||
const result = await this.runDeployScript(paramsFile, {
|
||||
rpcUrl,
|
||||
privateKey: dleParams.privateKey,
|
||||
networkId: deployParams.network,
|
||||
envNetworkKey: deployParams.network.toUpperCase()
|
||||
networkId: chainId.toString(),
|
||||
envNetworkKey: chainId.toString().toUpperCase()
|
||||
});
|
||||
|
||||
// Очищаем временные файлы
|
||||
@@ -94,61 +99,73 @@ class DLEV2Service {
|
||||
throw new Error('Местонахождение DLE обязательно');
|
||||
}
|
||||
|
||||
if (!params.partners || !Array.isArray(params.partners)) {
|
||||
if (!params.initialPartners || !Array.isArray(params.initialPartners)) {
|
||||
throw new Error('Партнеры должны быть массивом');
|
||||
}
|
||||
|
||||
if (!params.amounts || !Array.isArray(params.amounts)) {
|
||||
if (!params.initialAmounts || !Array.isArray(params.initialAmounts)) {
|
||||
throw new Error('Суммы должны быть массивом');
|
||||
}
|
||||
|
||||
if (params.partners.length !== params.amounts.length) {
|
||||
if (params.initialPartners.length !== params.initialAmounts.length) {
|
||||
throw new Error('Количество партнеров должно соответствовать количеству сумм распределения');
|
||||
}
|
||||
|
||||
if (params.partners.length === 0) {
|
||||
if (params.initialPartners.length === 0) {
|
||||
throw new Error('Должен быть указан хотя бы один партнер');
|
||||
}
|
||||
|
||||
if (params.quorumPercentage > 100) {
|
||||
throw new Error('Процент кворума не может превышать 100%');
|
||||
if (params.quorumPercentage > 100 || params.quorumPercentage < 1) {
|
||||
throw new Error('Процент кворума должен быть от 1% до 100%');
|
||||
}
|
||||
|
||||
// Проверяем адреса партнеров
|
||||
for (let i = 0; i < params.partners.length; i++) {
|
||||
if (!ethers.isAddress(params.partners[i])) {
|
||||
throw new Error(`Неверный адрес партнера ${i + 1}: ${params.partners[i]}`);
|
||||
for (let i = 0; i < params.initialPartners.length; i++) {
|
||||
if (!ethers.isAddress(params.initialPartners[i])) {
|
||||
throw new Error(`Неверный адрес партнера ${i + 1}: ${params.initialPartners[i]}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Проверяем, что выбраны сети
|
||||
if (!params.supportedChainIds || !Array.isArray(params.supportedChainIds) || params.supportedChainIds.length === 0) {
|
||||
throw new Error('Должна быть выбрана хотя бы одна сеть для деплоя');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Подготавливает параметры для деплоя
|
||||
* @param {Object} params - Параметры DLE
|
||||
* @returns {Object} - Подготовленные параметры
|
||||
* @param {Object} params - Параметры DLE из формы
|
||||
* @returns {Object} - Подготовленные параметры для скрипта деплоя
|
||||
*/
|
||||
prepareDeployParams(params) {
|
||||
// Создаем копию объекта, чтобы не изменять исходный
|
||||
const deployParams = { ...params };
|
||||
|
||||
// Преобразуем суммы из строк или чисел в BigNumber, если нужно
|
||||
deployParams.amounts = params.amounts.map(amount => {
|
||||
if (deployParams.initialAmounts && Array.isArray(deployParams.initialAmounts)) {
|
||||
deployParams.initialAmounts = deployParams.initialAmounts.map(amount => {
|
||||
if (typeof amount === 'string' && !amount.startsWith('0x')) {
|
||||
return ethers.parseEther(amount).toString();
|
||||
}
|
||||
return amount.toString();
|
||||
});
|
||||
}
|
||||
|
||||
// Преобразуем параметры голосования
|
||||
deployParams.votingDelay = params.votingDelay || 1;
|
||||
deployParams.votingPeriod = params.votingPeriod || 45818; // ~1 неделя
|
||||
deployParams.proposalThreshold = params.proposalThreshold || ethers.parseEther("100000").toString();
|
||||
deployParams.quorumPercentage = params.quorumPercentage || 4;
|
||||
deployParams.minTimelockDelay = params.minTimelockDelay || 2;
|
||||
// Убеждаемся, что okvedCodes - это массив
|
||||
if (!Array.isArray(deployParams.okvedCodes)) {
|
||||
deployParams.okvedCodes = [];
|
||||
}
|
||||
|
||||
// Убеждаемся, что isicCodes - это массив
|
||||
if (!Array.isArray(deployParams.isicCodes)) {
|
||||
deployParams.isicCodes = [];
|
||||
// Убеждаемся, что supportedChainIds - это массив
|
||||
if (!Array.isArray(deployParams.supportedChainIds)) {
|
||||
deployParams.supportedChainIds = [1]; // По умолчанию Ethereum
|
||||
}
|
||||
|
||||
// Устанавливаем currentChainId как первую выбранную сеть
|
||||
if (deployParams.supportedChainIds.length > 0) {
|
||||
deployParams.currentChainId = deployParams.supportedChainIds[0];
|
||||
} else {
|
||||
deployParams.currentChainId = 1; // По умолчанию Ethereum
|
||||
}
|
||||
|
||||
return deployParams;
|
||||
@@ -244,20 +261,18 @@ class DLEV2Service {
|
||||
extractDeployResult(stdout) {
|
||||
// Ищем строки с адресами в выводе
|
||||
const dleAddressMatch = stdout.match(/DLE v2 задеплоен по адресу: (0x[a-fA-F0-9]{40})/);
|
||||
const timelockAddressMatch = stdout.match(/Таймлок создан по адресу: (0x[a-fA-F0-9]{40})/);
|
||||
|
||||
if (dleAddressMatch && timelockAddressMatch) {
|
||||
if (dleAddressMatch) {
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
dleAddress: dleAddressMatch[1],
|
||||
timelockAddress: timelockAddressMatch[1],
|
||||
version: 'v2'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error('Не удалось извлечь адреса из вывода скрипта');
|
||||
throw new Error('Не удалось извлечь адрес DLE из вывода скрипта');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -77,9 +77,9 @@ class EncryptedDataService {
|
||||
const originalName = col.column_name.replace('_encrypted', '');
|
||||
// console.log(`🔓 Расшифровываем поле ${col.column_name} -> ${originalName}`);
|
||||
if (col.data_type === 'jsonb') {
|
||||
return `decrypt_json(${col.column_name}, $1) as "${originalName}"`;
|
||||
return `CASE WHEN ${col.column_name} IS NULL OR ${col.column_name} = '' THEN NULL ELSE decrypt_json(${col.column_name}, $1) END as "${originalName}"`;
|
||||
} else {
|
||||
return `decrypt_text(${col.column_name}, $1) as "${originalName}"`;
|
||||
return `CASE WHEN ${col.column_name} IS NULL OR ${col.column_name} = '' THEN NULL ELSE decrypt_text(${col.column_name}, $1) END as "${originalName}"`;
|
||||
}
|
||||
} else if (!col.column_name.includes('_encrypted')) {
|
||||
// Проверяем, есть ли зашифрованная версия этой колонки
|
||||
@@ -181,6 +181,13 @@ class EncryptedDataService {
|
||||
return rows;
|
||||
} catch (error) {
|
||||
// console.error(`❌ Ошибка получения данных из ${tableName}:`, error);
|
||||
|
||||
// Если ошибка связана с расшифровкой, попробуем получить данные без расшифровки
|
||||
if (error.message && error.message.includes('invalid base64')) {
|
||||
console.log(`⚠️ Ошибка расшифровки в ${tableName}, пытаемся получить данные без расшифровки`);
|
||||
return await this.executeUnencryptedQuery(tableName, conditions, limit, orderBy);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -230,17 +237,18 @@ class EncryptedDataService {
|
||||
// Проверяем, что значение не пустое перед шифрованием
|
||||
if (value === null || value === undefined || (typeof value === 'string' && value.trim() === '')) {
|
||||
// Пропускаем пустые значения
|
||||
// console.log(`⚠️ Пропускаем пустое зашифрованное поле ${key}`);
|
||||
console.log(`⚠️ Пропускаем пустое зашифрованное поле ${key}`);
|
||||
continue;
|
||||
}
|
||||
const currentParamIndex = paramIndex++;
|
||||
filteredData[key] = value; // Добавляем в отфильтрованные данные
|
||||
// console.log(`✅ Добавили зашифрованное поле ${key} в filteredData`);
|
||||
console.log(`✅ Добавили зашифрованное поле ${key} = "${value}" в filteredData`);
|
||||
if (encryptedColumn.data_type === 'jsonb') {
|
||||
encryptedData[`${key}_encrypted`] = `encrypt_json($${currentParamIndex}, ${hasEncryptedFields ? '$1::text' : 'NULL'})`;
|
||||
} else {
|
||||
encryptedData[`${key}_encrypted`] = `encrypt_text($${currentParamIndex}, ${hasEncryptedFields ? '$1::text' : 'NULL'})`;
|
||||
}
|
||||
console.log(`🔐 Будем шифровать ${key} -> ${key}_encrypted`);
|
||||
} else if (unencryptedColumn) {
|
||||
// Если есть незашифрованная колонка, сохраняем как есть
|
||||
// Проверяем, что значение не пустое перед сохранением (кроме role и sender_type)
|
||||
@@ -297,6 +305,10 @@ class EncryptedDataService {
|
||||
const query = `INSERT INTO ${tableName} (${columns.join(', ')}) VALUES (${placeholders}) RETURNING *`;
|
||||
const params = hasEncryptedFields ? [this.encryptionKey, ...Object.values(filteredData)] : [...Object.values(filteredData)];
|
||||
|
||||
console.log(`🔍 Выполняем INSERT запрос:`, query);
|
||||
console.log(`🔍 Параметры:`, params);
|
||||
console.log(`🔍 Ключ шифрования:`, this.encryptionKey ? 'установлен' : 'не установлен');
|
||||
|
||||
const { rows } = await db.getQuery()(query, params);
|
||||
return rows[0];
|
||||
}
|
||||
|
||||
@@ -151,12 +151,36 @@ class IdentityService {
|
||||
try {
|
||||
const identities = await encryptedDb.getData('user_identities', { user_id: userId });
|
||||
logger.info(`[IdentityService] Found ${identities.length} identities for user ${userId}`);
|
||||
return identities;
|
||||
|
||||
// Данные уже расшифрованы encryptedDb, просто переименовываем поля
|
||||
const formattedIdentities = identities.map(identity => ({
|
||||
id: identity.id,
|
||||
user_id: identity.user_id,
|
||||
created_at: identity.created_at,
|
||||
provider: identity.provider, // Уже расшифровано
|
||||
provider_id: identity.provider_id // Уже расшифровано
|
||||
}));
|
||||
|
||||
return formattedIdentities;
|
||||
} catch (error) {
|
||||
logger.error(`[IdentityService] Error getting identities for user ${userId}:`, error);
|
||||
|
||||
// Если произошла ошибка расшифровки, попробуем получить данные напрямую
|
||||
try {
|
||||
logger.info(`[IdentityService] Trying to get unencrypted data for user ${userId}`);
|
||||
const { rows } = await db.getQuery()(
|
||||
'SELECT id, user_id, created_at, provider_encrypted as provider, provider_id_encrypted as provider_id FROM user_identities WHERE user_id = $1',
|
||||
[userId]
|
||||
);
|
||||
|
||||
logger.info(`[IdentityService] Found ${rows.length} unencrypted identities for user ${userId}`);
|
||||
return rows;
|
||||
} catch (fallbackError) {
|
||||
logger.error(`[IdentityService] Fallback error getting identities for user ${userId}:`, fallbackError);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает идентификаторы пользователя по типу провайдера
|
||||
|
||||
@@ -62,4 +62,9 @@ async function getRpcUrlByNetworkId(networkId) {
|
||||
return providers[0]?.rpc_url || null;
|
||||
}
|
||||
|
||||
module.exports = { getAllRpcProviders, saveAllRpcProviders, upsertRpcProvider, deleteRpcProvider, getRpcUrlByNetworkId };
|
||||
async function getRpcUrlByChainId(chainId) {
|
||||
const providers = await encryptedDb.getData('rpc_providers', { chain_id: chainId }, 1);
|
||||
return providers[0]?.rpc_url || null;
|
||||
}
|
||||
|
||||
module.exports = { getAllRpcProviders, saveAllRpcProviders, upsertRpcProvider, deleteRpcProvider, getRpcUrlByNetworkId, getRpcUrlByChainId };
|
||||
@@ -56,25 +56,14 @@ async function checkUserIdentity(userId, provider, providerId) {
|
||||
|
||||
// Добавление новой идентификации
|
||||
async function addUserIdentity(userId, provider, providerId) {
|
||||
// Получаем ключ шифрования
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
let encryptionKey = 'default-key';
|
||||
const encryptedDb = require('../services/encryptedDatabaseService');
|
||||
|
||||
try {
|
||||
const keyPath = path.join(__dirname, '../ssl/keys/full_db_encryption.key');
|
||||
if (fs.existsSync(keyPath)) {
|
||||
encryptionKey = fs.readFileSync(keyPath, 'utf8').trim();
|
||||
}
|
||||
} catch (keyError) {
|
||||
console.error('Error reading encryption key:', keyError);
|
||||
}
|
||||
|
||||
try {
|
||||
await db.getQuery()(
|
||||
'INSERT INTO user_identities (user_id, provider_encrypted, provider_id_encrypted) VALUES ($1, encrypt_text($2, $4), encrypt_text($3, $4))',
|
||||
[userId, provider, providerId, encryptionKey]
|
||||
);
|
||||
await encryptedDb.saveData('user_identities', {
|
||||
user_id: userId,
|
||||
provider: provider,
|
||||
provider_id: providerId
|
||||
});
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (error.code === '23505') {
|
||||
|
||||
@@ -10,76 +10,63 @@
|
||||
* GitHub: https://github.com/HB3-ACCELERATOR
|
||||
*/
|
||||
|
||||
import api from '@/api/axios';
|
||||
// Сервис для работы с DLE v2
|
||||
import axios from 'axios';
|
||||
|
||||
/**
|
||||
* Сервис для работы с DLE v2 (Digital Legal Entity)
|
||||
* Современный подход с единым контрактом
|
||||
*/
|
||||
class DLEV2Service {
|
||||
/**
|
||||
* Создает новое DLE v2
|
||||
* @param {Object} dleParams - Параметры DLE
|
||||
* @returns {Promise<Object>} - Результат создания
|
||||
*/
|
||||
async createDLE(dleParams) {
|
||||
export const createDLE = async (dleParams) => {
|
||||
try {
|
||||
const response = await api.post('/dle-v2', dleParams);
|
||||
const response = await axios.post('/api/dle-v2', dleParams);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
// console.error('Ошибка при создании DLE v2:', error);
|
||||
console.error('Ошибка при создании DLE:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Получает список всех DLE v2
|
||||
* @returns {Promise<Array>} - Список DLE v2
|
||||
* @returns {Promise<Object>} - Список DLE
|
||||
*/
|
||||
async getAllDLEs() {
|
||||
export const getAllDLEs = async () => {
|
||||
try {
|
||||
const response = await api.get('/dle-v2');
|
||||
return response.data.data || [];
|
||||
} catch (error) {
|
||||
// console.error('Ошибка при получении списка DLE v2:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает настройки по умолчанию для DLE v2
|
||||
* @returns {Promise<Object>} - Настройки по умолчанию
|
||||
*/
|
||||
async getDefaults() {
|
||||
try {
|
||||
const response = await api.get('/dle-v2/defaults');
|
||||
return response.data.data;
|
||||
} catch (error) {
|
||||
// console.error('Ошибка при получении настроек по умолчанию DLE v2:', error);
|
||||
return {
|
||||
votingDelay: 1,
|
||||
votingPeriod: 45818,
|
||||
proposalThreshold: '100000',
|
||||
quorumPercentage: 4,
|
||||
minTimelockDelay: 2
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаляет DLE v2 по адресу
|
||||
* @param {string} dleAddress - Адрес DLE
|
||||
* @returns {Promise<Object>} - Результат удаления
|
||||
*/
|
||||
async deleteDLE(dleAddress) {
|
||||
try {
|
||||
const response = await api.delete(`/dle-v2/${dleAddress}`);
|
||||
const response = await axios.get('/api/dle-v2');
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
// console.error('Ошибка при удалении DLE v2:', error);
|
||||
console.error('Ошибка при получении списка DLE:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default new DLEV2Service();
|
||||
/**
|
||||
* Получает информацию о конкретном DLE v2
|
||||
* @param {string} dleAddress - Адрес DLE
|
||||
* @returns {Promise<Object>} - Информация о DLE
|
||||
*/
|
||||
export const getDLEInfo = async (dleAddress) => {
|
||||
try {
|
||||
const response = await axios.get(`/api/dle-v2/${dleAddress}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Ошибка при получении информации о DLE:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Получает параметры по умолчанию для создания DLE v2
|
||||
* @returns {Promise<Object>} - Параметры по умолчанию
|
||||
*/
|
||||
export const getDefaultParams = async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/dle-v2/default-params');
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Ошибка при получении параметров по умолчанию:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
@@ -569,6 +569,9 @@
|
||||
v-model="unifiedPrivateKey"
|
||||
class="form-control"
|
||||
placeholder="Введите приватный ключ (0x... или без префикса)"
|
||||
@input="() => { console.log('Input event triggered'); validatePrivateKey('unified'); }"
|
||||
@focus="() => console.log('Input field focused')"
|
||||
@blur="() => console.log('Input field blurred')"
|
||||
>
|
||||
<span class="input-icon" @click="showUnifiedKey = !showUnifiedKey">
|
||||
<i :class="showUnifiedKey ? 'fas fa-eye-slash' : 'fas fa-eye'"></i>
|
||||
@@ -1951,15 +1954,18 @@ const toggleKeyVisibility = (chainId) => {
|
||||
};
|
||||
|
||||
// Валидация приватного ключа с дебаунсом
|
||||
const validatePrivateKey = (chainId) => {
|
||||
const validatePrivateKey = async (chainId) => {
|
||||
console.log('Функция validatePrivateKey вызвана для chainId:', chainId);
|
||||
|
||||
// Очищаем предыдущий таймер
|
||||
if (validatePrivateKey.timeout) {
|
||||
clearTimeout(validatePrivateKey.timeout);
|
||||
}
|
||||
|
||||
// Устанавливаем новый таймер для дебаунса
|
||||
validatePrivateKey.timeout = setTimeout(() => {
|
||||
validatePrivateKey.timeout = setTimeout(async () => {
|
||||
const key = chainId === 'unified' ? unifiedPrivateKey.value : privateKeys[chainId];
|
||||
console.log('Ключ для валидации:', key);
|
||||
|
||||
if (!key) {
|
||||
keyValidation[chainId] = null;
|
||||
@@ -1967,26 +1973,33 @@ const validatePrivateKey = (chainId) => {
|
||||
}
|
||||
|
||||
try {
|
||||
// Простая валидация длины и формата
|
||||
const cleanKey = key.startsWith('0x') ? key.slice(2) : key;
|
||||
// Логируем отправляемый ключ (только для отладки)
|
||||
console.log('Отправляем приватный ключ для валидации:', key);
|
||||
console.log('Длина ключа:', key.length);
|
||||
console.log('Полный ключ:', key);
|
||||
|
||||
if (cleanKey.length === 64 && /^[a-fA-F0-9]+$/.test(cleanKey)) {
|
||||
// Генерируем адрес из приватного ключа (упрощенная версия)
|
||||
const address = '0x' + cleanKey.substring(0, 40);
|
||||
// Отправляем запрос на бэкенд для валидации
|
||||
const response = await axios.post('/api/dle-v2/validate-private-key', {
|
||||
privateKey: key
|
||||
});
|
||||
|
||||
keyValidation[chainId] = {
|
||||
isValid: true,
|
||||
address: address,
|
||||
error: null
|
||||
};
|
||||
console.log('Ответ от сервера:', response.data);
|
||||
|
||||
if (response.data.success) {
|
||||
keyValidation[chainId] = response.data.data;
|
||||
} else {
|
||||
throw new Error('Некорректный формат ключа');
|
||||
}
|
||||
} catch (error) {
|
||||
keyValidation[chainId] = {
|
||||
isValid: false,
|
||||
address: null,
|
||||
error: 'Некорректный приватный ключ'
|
||||
error: response.data.message
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Ошибка валидации приватного ключа:', error);
|
||||
keyValidation[chainId] = {
|
||||
isValid: false,
|
||||
address: null,
|
||||
error: error.response?.data?.message || 'Ошибка валидации приватного ключа'
|
||||
};
|
||||
}
|
||||
}, 300); // Задержка 300мс
|
||||
@@ -2107,6 +2120,9 @@ watch([() => dleSettings.name, () => dleSettings.tokenSymbol, selectedNetworks],
|
||||
|
||||
// Инициализация
|
||||
onMounted(() => {
|
||||
console.log('🚀 DleDeployFormView компонент загружен - ТЕСТ ОБНОВЛЕНИЯ');
|
||||
alert('Компонент загружен - проверьте консоль');
|
||||
|
||||
// Загружаем список стран
|
||||
loadCountries();
|
||||
|
||||
@@ -2209,7 +2225,10 @@ const deploySmartContracts = async () => {
|
||||
supportedChainIds: dleSettings.selectedNetworks || [],
|
||||
|
||||
// Текущая цепочка (будет установлена при деплое)
|
||||
currentChainId: dleSettings.selectedNetworks[0] || 1
|
||||
currentChainId: dleSettings.selectedNetworks[0] || 1,
|
||||
|
||||
// Приватный ключ для деплоя
|
||||
privateKey: unifiedPrivateKey.value
|
||||
};
|
||||
|
||||
console.log('Данные для деплоя DLE:', deployData);
|
||||
@@ -2247,6 +2266,9 @@ const isFormValid = computed(() => {
|
||||
dleSettings.governanceQuorum > 0 &&
|
||||
dleSettings.governanceQuorum <= 100 &&
|
||||
dleSettings.selectedNetworks.length > 0 &&
|
||||
// Проверка приватного ключа
|
||||
unifiedPrivateKey.value &&
|
||||
keyValidation.unified?.isValid &&
|
||||
// Валидация координат
|
||||
validateCoordinates(dleSettings.coordinates)
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user