Описание изменений
This commit is contained in:
@@ -1,172 +1,14 @@
|
||||
const { ethers } = require('ethers');
|
||||
require('dotenv').config();
|
||||
const db = require('../db');
|
||||
const contractArtifact = require('../artifacts/contracts/MyContract.sol/MyContract.json');
|
||||
const contractABI = contractArtifact.abi;
|
||||
const logger = require('./logger');
|
||||
const { getContract } = require('./contracts');
|
||||
|
||||
// Проверяем наличие необходимых переменных окружения
|
||||
if (!process.env.ACCESS_TOKEN_ADDRESS) {
|
||||
console.error('ACCESS_TOKEN_ADDRESS не указан в .env файле');
|
||||
}
|
||||
|
||||
if (!process.env.ETHEREUM_NETWORK_URL) {
|
||||
console.error('ETHEREUM_NETWORK_URL не указан в .env файле');
|
||||
}
|
||||
|
||||
// Подключение к контракту
|
||||
const provider = new ethers.JsonRpcProvider(process.env.ETHEREUM_NETWORK_URL);
|
||||
let accessToken;
|
||||
|
||||
try {
|
||||
const AccessTokenABI = require('../artifacts/contracts/AccessToken.sol/AccessToken.json').abi;
|
||||
accessToken = new ethers.Contract(process.env.ACCESS_TOKEN_ADDRESS, AccessTokenABI, provider);
|
||||
} catch (error) {
|
||||
console.error('Ошибка инициализации контракта AccessToken:', error);
|
||||
}
|
||||
const authService = require('../services/auth-service');
|
||||
|
||||
/**
|
||||
* Проверяет доступ и роль пользователя
|
||||
* @param {string} address - Ethereum адрес пользователя
|
||||
* @returns {Promise<{hasAccess: boolean, role: string|null}>}
|
||||
*/
|
||||
async function checkAccess(address) {
|
||||
try {
|
||||
if (!address || !accessToken) {
|
||||
return { hasAccess: false, role: null };
|
||||
}
|
||||
|
||||
// Проверяем активный токен
|
||||
const activeTokenId = await accessToken.activeTokens(address);
|
||||
if (activeTokenId.toString() === '0') {
|
||||
return { hasAccess: false, role: null };
|
||||
}
|
||||
|
||||
// Получаем роль
|
||||
const roleId = await accessToken.checkRole(address);
|
||||
const roles = ['ADMIN', 'MODERATOR', 'SUPPORT'];
|
||||
const role = roles[roleId];
|
||||
|
||||
return {
|
||||
hasAccess: true,
|
||||
role,
|
||||
tokenId: activeTokenId.toString(),
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Access check error:', error);
|
||||
return { hasAccess: false, role: null };
|
||||
}
|
||||
}
|
||||
|
||||
// Функция для проверки, является ли пользователь администратором
|
||||
async function checkIfAdmin(address) {
|
||||
try {
|
||||
console.log('Проверка прав администратора для адреса:', address);
|
||||
|
||||
// Проверяем в базе данных
|
||||
const result = await db.query('SELECT is_admin FROM users WHERE address = $1', [address]);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
console.log(`Пользователь с адресом ${address} не найден в базе данных`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const isAdmin = result.rows[0].is_admin;
|
||||
console.log(`Пользователь с адресом ${address} имеет статус администратора:`, isAdmin);
|
||||
|
||||
return isAdmin;
|
||||
} catch (error) {
|
||||
console.error('Ошибка при проверке прав администратора:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет баланс токенов пользователя и обновляет его роль
|
||||
* @param {string} address - Адрес кошелька пользователя
|
||||
* @returns {Promise<boolean>} - Имеет ли пользователь права администратора
|
||||
*/
|
||||
async function checkTokenBalanceAndUpdateRole(address) {
|
||||
try {
|
||||
// Получение контракта токенов
|
||||
const accessTokenContract = await getContract('AccessToken');
|
||||
|
||||
// Проверка баланса
|
||||
const balance = await accessTokenContract.balanceOf(address);
|
||||
|
||||
// Минимальное количество токенов для прав администратора
|
||||
const minTokens = ethers.utils.parseUnits(process.env.MIN_ADMIN_TOKENS || "1", 18);
|
||||
|
||||
const isAdmin = balance.gte(minTokens);
|
||||
|
||||
// Получение ID пользователя по адресу кошелька
|
||||
const userResult = await db.query(`
|
||||
SELECT u.id FROM users u
|
||||
JOIN user_identities ui ON u.id = ui.user_id
|
||||
WHERE ui.identity_type = 'wallet' AND ui.identity_value = $1
|
||||
`, [address.toLowerCase()]);
|
||||
|
||||
if (userResult.rows.length > 0) {
|
||||
const userId = userResult.rows[0].id;
|
||||
|
||||
// Получение ID роли
|
||||
const roleResult = await db.query(
|
||||
'SELECT id FROM roles WHERE name = $1',
|
||||
[isAdmin ? 'admin' : 'user']
|
||||
);
|
||||
|
||||
if (roleResult.rows.length > 0) {
|
||||
const roleId = roleResult.rows[0].id;
|
||||
|
||||
// Обновление роли пользователя
|
||||
await db.query(
|
||||
'UPDATE users SET role_id = $1, last_token_check = NOW() WHERE id = $2',
|
||||
[roleId, userId]
|
||||
);
|
||||
|
||||
logger.info(`Updated user ${userId} role to ${isAdmin ? 'admin' : 'user'} based on token balance`);
|
||||
}
|
||||
}
|
||||
|
||||
return isAdmin;
|
||||
} catch (error) {
|
||||
logger.error(`Error checking token balance for ${address}: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает информацию о пользователе, включая его роль
|
||||
* @param {number} userId - ID пользователя
|
||||
* @returns {Promise<Object>} - Информация о пользователе
|
||||
*/
|
||||
async function getUserInfo(userId) {
|
||||
try {
|
||||
const result = await db.query(`
|
||||
SELECT u.id, u.username, u.preferred_language, r.name as role
|
||||
FROM users u
|
||||
LEFT JOIN roles r ON u.role_id = r.id
|
||||
WHERE u.id = $1
|
||||
`, [userId]);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return result.rows[0];
|
||||
} catch (error) {
|
||||
logger.error(`Error getting user info for ${userId}: ${error.message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Запускает проверку токенов для всех пользователей
|
||||
* Проверяет токены всех пользователей и обновляет их роли
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function checkAllUsersTokens() {
|
||||
try {
|
||||
// Получение всех пользователей с кошельками
|
||||
// Получаем всех пользователей с кошельками
|
||||
const walletUsers = await db.query(`
|
||||
SELECT u.id, ui.identity_value as address
|
||||
FROM users u
|
||||
@@ -174,23 +16,24 @@ async function checkAllUsersTokens() {
|
||||
WHERE ui.identity_type = 'wallet'
|
||||
`);
|
||||
|
||||
logger.info(`Checking token balances for ${walletUsers.rows.length} users`);
|
||||
logger.info(`Checking tokens for ${walletUsers.rows.length} users`);
|
||||
|
||||
for (const user of walletUsers.rows) {
|
||||
// Проверка баланса токенов
|
||||
const hasTokens = await checkTokenBalanceAndUpdateRole(user.address);
|
||||
|
||||
logger.info(`User ${user.id} with address ${user.address}: admin=${hasTokens}`);
|
||||
try {
|
||||
// Используем существующий метод для проверки токенов и обновления роли
|
||||
const isAdmin = await authService.checkTokensAndUpdateRole(user.address);
|
||||
logger.info(`Updated user ${user.id} with address ${user.address}: admin=${isAdmin}`);
|
||||
} catch (error) {
|
||||
logger.error(`Error checking tokens for user ${user.id}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info('Token check completed');
|
||||
} catch (error) {
|
||||
logger.error(`Error checking token balances: ${error.message}`);
|
||||
logger.error(`Error checking all users tokens: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
checkAccess,
|
||||
checkIfAdmin,
|
||||
checkTokenBalanceAndUpdateRole,
|
||||
getUserInfo,
|
||||
checkAllUsersTokens
|
||||
};
|
||||
};
|
||||
@@ -1,184 +1,152 @@
|
||||
const { SiweMessage } = require('siwe');
|
||||
const { ethers } = require('ethers');
|
||||
const AccessTokenABI = require('../artifacts/contracts/AccessToken.sol/AccessToken.json').abi;
|
||||
require('dotenv').config();
|
||||
const { pool } = require('../db');
|
||||
const db = require('../db');
|
||||
const logger = require('./logger');
|
||||
const authService = require('../services/auth-service');
|
||||
const { USER_ROLES, IDENTITY_TYPES } = require('./constants');
|
||||
|
||||
// В ethers.js v6.x используется JsonRpcProvider напрямую
|
||||
// Инициализация провайдера
|
||||
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
|
||||
const accessToken = new ethers.Contract(process.env.ACCESS_TOKEN_ADDRESS, AccessTokenABI, provider);
|
||||
|
||||
// Проверяем наличие адреса контракта
|
||||
if (!process.env.ACCESS_TOKEN_ADDRESS) {
|
||||
console.error('ACCESS_TOKEN_ADDRESS не указан в .env файле');
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет подпись сообщения
|
||||
* @param {Object} message - Сообщение для проверки
|
||||
* @param {string} signature - Подпись сообщения
|
||||
* @param {string} nonce - Независимый идентификатор
|
||||
* @param {string} signature - Подпись
|
||||
* @param {string} address - Адрес кошелька
|
||||
* @returns {Promise<boolean>} - Результат проверки
|
||||
*/
|
||||
async function verifySignature(message, signature, address) {
|
||||
async function verifySignature(nonce, signature, address) {
|
||||
try {
|
||||
// Формируем сообщение для проверки
|
||||
const domain = message.domain || 'localhost';
|
||||
const statement = message.statement || 'Sign in with Ethereum to the app.';
|
||||
const uri = message.uri || 'http://localhost:8000';
|
||||
const version = message.version || '1';
|
||||
const chainId = message.chainId || '1';
|
||||
const nonce = message.nonce;
|
||||
|
||||
const messageToVerify = `${domain} wants you to sign in with your Ethereum account:
|
||||
${address}
|
||||
|
||||
${statement}
|
||||
|
||||
URI: ${uri}
|
||||
Version: ${version}
|
||||
Chain ID: ${chainId}
|
||||
Nonce: ${nonce}
|
||||
`;
|
||||
|
||||
// В ethers.js v6.x используется verifyMessage напрямую
|
||||
const recoveredAddress = ethers.verifyMessage(messageToVerify, signature);
|
||||
|
||||
// Создаем сообщение для проверки
|
||||
const message = `Sign this message to authenticate with our app: ${nonce}`;
|
||||
|
||||
// Восстанавливаем адрес из подписи
|
||||
const recoveredAddress = ethers.verifyMessage(message, signature);
|
||||
|
||||
// Проверяем, что восстановленный адрес совпадает с предоставленным
|
||||
return recoveredAddress.toLowerCase() === address.toLowerCase();
|
||||
} catch (error) {
|
||||
console.error('Signature verification error:', error);
|
||||
console.error('Error verifying signature:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function checkAccess(address) {
|
||||
// Временная заглушка
|
||||
return { hasAccess: false, role: null };
|
||||
}
|
||||
|
||||
async function verifyAndCheckAccess(message, signature, address) {
|
||||
// Проверяем подпись
|
||||
const verified = await verifySignature(message, signature, address);
|
||||
if (!verified) {
|
||||
return {
|
||||
verified: false,
|
||||
access: { hasAccess: false },
|
||||
};
|
||||
}
|
||||
|
||||
// Проверяем доступ
|
||||
const access = await checkAccess(address);
|
||||
|
||||
return {
|
||||
verified: true,
|
||||
access,
|
||||
};
|
||||
}
|
||||
|
||||
// Функция для поиска или создания пользователя
|
||||
async function findOrCreateUser(identifier, identityType = 'wallet') {
|
||||
/**
|
||||
* Проверяет, является ли пользователь администратором
|
||||
* @param {string} address - Адрес кошелька
|
||||
* @returns {Promise<boolean>} - Является ли пользователь администратором
|
||||
*/
|
||||
async function checkUserRole(address) {
|
||||
try {
|
||||
// Проверяем, является ли адрес адресом администратора
|
||||
const isAdmin = identityType === 'wallet' &&
|
||||
identifier.toLowerCase() === process.env.ADMIN_WALLET_ADDRESS.toLowerCase();
|
||||
// Проверяем наличие токена администратора
|
||||
const isAdmin = await authService.checkAdminToken(address);
|
||||
return isAdmin;
|
||||
} catch (error) {
|
||||
console.error('Error checking user role:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет доступ пользователя
|
||||
* @param {string} walletAddress - Адрес кошелька
|
||||
* @returns {Promise<Object>} - Информация о доступе
|
||||
*/
|
||||
async function checkAccess(walletAddress) {
|
||||
try {
|
||||
// Проверяем наличие токена администратора
|
||||
const isAdmin = await authService.checkAdminToken(walletAddress);
|
||||
|
||||
console.log(`Проверка на администратора: ${identifier.toLowerCase()} === ${process.env.ADMIN_WALLET_ADDRESS.toLowerCase()} = ${isAdmin}`);
|
||||
// Получаем или создаем пользователя
|
||||
const userId = await findOrCreateUser(walletAddress);
|
||||
|
||||
// Проверяем, существует ли пользователь с таким идентификатором
|
||||
const identityResult = await pool.query(
|
||||
'SELECT user_id FROM user_identities WHERE identity_type = $1 AND identity_value = $2',
|
||||
[identityType, identifier.toLowerCase()]
|
||||
);
|
||||
|
||||
let userId;
|
||||
let isNewUser = false;
|
||||
|
||||
if (identityResult.rows.length > 0) {
|
||||
// Пользователь найден
|
||||
userId = identityResult.rows[0].user_id;
|
||||
console.log(`Найден существующий пользователь с ID: ${userId}`);
|
||||
|
||||
// Обновляем статус администратора, если это необходимо
|
||||
if (isAdmin) {
|
||||
await pool.query(
|
||||
'UPDATE users SET is_admin = true WHERE id = $1',
|
||||
[userId]
|
||||
);
|
||||
console.log(`Обновлен статус администратора для пользователя ${userId}`);
|
||||
}
|
||||
} else {
|
||||
// Создаем нового пользователя с явным указанием всех необходимых полей
|
||||
const username = `user_${Date.now()}`;
|
||||
|
||||
// Проверяем существование роли USER или ADMIN
|
||||
const roleName = isAdmin ? 'ADMIN' : 'USER';
|
||||
const roleCheck = await pool.query('SELECT id FROM roles WHERE name = $1', [roleName]);
|
||||
let roleId;
|
||||
|
||||
if (roleCheck.rows.length > 0) {
|
||||
roleId = roleCheck.rows[0].id;
|
||||
} else {
|
||||
// Если роли нет, создаем её
|
||||
const newRole = await pool.query(
|
||||
'INSERT INTO roles (name, description) VALUES ($1, $2) RETURNING id',
|
||||
[roleName, isAdmin ? 'Administrator role' : 'Regular user role']
|
||||
);
|
||||
roleId = newRole.rows[0].id;
|
||||
}
|
||||
|
||||
// Создаем пользователя с обязательными полями
|
||||
const userResult = await pool.query(
|
||||
`INSERT INTO users (username, role_id, address, created_at, is_admin)
|
||||
VALUES ($1, $2, $3, NOW(), $4)
|
||||
RETURNING id`,
|
||||
[username, roleId, identifier.toLowerCase(), isAdmin]
|
||||
);
|
||||
|
||||
userId = userResult.rows[0].id;
|
||||
isNewUser = true;
|
||||
|
||||
// Создаем запись в таблице идентификаторов
|
||||
await pool.query(
|
||||
'INSERT INTO user_identities (user_id, identity_type, identity_value, verified, created_at) VALUES ($1, $2, $3, true, NOW())',
|
||||
[userId, identityType, identifier.toLowerCase()]
|
||||
);
|
||||
|
||||
console.log(`Создан новый пользователь с ID: ${userId}, isAdmin: ${isAdmin}`);
|
||||
}
|
||||
|
||||
// Получаем информацию о пользователе
|
||||
try {
|
||||
const userInfo = await pool.query(
|
||||
`SELECT u.id, u.username, u.is_admin, r.name as role
|
||||
FROM users u
|
||||
JOIN roles r ON u.role_id = r.id
|
||||
WHERE u.id = $1`,
|
||||
[userId]
|
||||
);
|
||||
|
||||
if (userInfo.rows.length > 0) {
|
||||
return userInfo.rows[0];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Ошибка при получении информации о пользователе:', err);
|
||||
}
|
||||
|
||||
// Если не удалось получить полную информацию, возвращаем базовую
|
||||
return {
|
||||
id: userId,
|
||||
username: isNewUser ? `user_${Date.now()}` : 'unknown',
|
||||
is_admin: isAdmin,
|
||||
role: isAdmin ? 'ADMIN' : 'USER'
|
||||
userId,
|
||||
isAdmin,
|
||||
hasAccess: true
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Ошибка при поиске/создании пользователя:', error);
|
||||
logger.error(`Error checking access: ${error.message}`);
|
||||
return {
|
||||
hasAccess: false,
|
||||
error: error.message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Находит или создает пользователя по адресу кошелька
|
||||
* @param {string} address - Адрес кошелька
|
||||
* @returns {Promise<Object>} - ID пользователя и роль
|
||||
*/
|
||||
async function findOrCreateUser(address) {
|
||||
try {
|
||||
// Проверяем, существует ли пользователь
|
||||
const userResult = await db.query('SELECT * FROM users WHERE LOWER(address) = LOWER($1)', [address]);
|
||||
|
||||
let userId;
|
||||
let isAdmin = false;
|
||||
|
||||
if (userResult.rows.length === 0) {
|
||||
// Если пользователь не найден, создаем его
|
||||
// Получаем ID роли 'user'
|
||||
const roleResult = await db.query('SELECT id FROM roles WHERE name = $1', ['user']);
|
||||
if (roleResult.rows.length === 0) {
|
||||
throw new Error('Role "user" not found');
|
||||
}
|
||||
const roleId = roleResult.rows[0].id;
|
||||
|
||||
// Создаем пользователя с ролью 'user'
|
||||
const newUserResult = await db.query(
|
||||
'INSERT INTO users (address, role_id, created_at) VALUES (LOWER($1), $2, NOW()) RETURNING id',
|
||||
[address, roleId]
|
||||
);
|
||||
|
||||
userId = newUserResult.rows[0].id;
|
||||
|
||||
// Проверяем, является ли пользователь администратором
|
||||
isAdmin = await checkUserRole(address);
|
||||
|
||||
// Если пользователь администратор, обновляем его роль
|
||||
if (isAdmin) {
|
||||
const adminRoleResult = await db.query('SELECT id FROM roles WHERE name = $1', ['admin']);
|
||||
if (adminRoleResult.rows.length > 0) {
|
||||
const adminRoleId = adminRoleResult.rows[0].id;
|
||||
await db.query('UPDATE users SET role_id = $1 WHERE id = $2', [adminRoleId, userId]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Если пользователь найден, получаем его ID и роль
|
||||
userId = userResult.rows[0].id;
|
||||
|
||||
// Проверяем, является ли пользователь администратором по роли
|
||||
const roleResult = await db.query('SELECT name FROM roles WHERE id = $1', [userResult.rows[0].role_id]);
|
||||
isAdmin = roleResult.rows.length > 0 && roleResult.rows[0].name === 'admin';
|
||||
|
||||
// Проверяем, является ли пользователь администратором по токену
|
||||
const isAdminByToken = await checkUserRole(address);
|
||||
|
||||
// Обновляем роль пользователя, если она изменилась
|
||||
if (isAdminByToken !== isAdmin) {
|
||||
const roleNameToSet = isAdminByToken ? 'admin' : 'user';
|
||||
const roleToSetResult = await db.query('SELECT id FROM roles WHERE name = $1', [roleNameToSet]);
|
||||
if (roleToSetResult.rows.length > 0) {
|
||||
const roleIdToSet = roleToSetResult.rows[0].id;
|
||||
await db.query('UPDATE users SET role_id = $1 WHERE id = $2', [roleIdToSet, userId]);
|
||||
isAdmin = isAdminByToken;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { userId, isAdmin };
|
||||
} catch (error) {
|
||||
console.error('Error finding or creating user:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
verifyAndCheckAccess,
|
||||
verifySignature,
|
||||
checkAccess,
|
||||
findOrCreateUser
|
||||
};
|
||||
findOrCreateUser,
|
||||
checkUserRole
|
||||
};
|
||||
58
backend/utils/constants.js
Normal file
58
backend/utils/constants.js
Normal file
@@ -0,0 +1,58 @@
|
||||
// Роли пользователей
|
||||
const USER_ROLES = {
|
||||
USER: 1,
|
||||
ADMIN: 2
|
||||
};
|
||||
|
||||
// Типы идентификаторов
|
||||
const IDENTITY_TYPES = {
|
||||
WALLET: 'wallet',
|
||||
EMAIL: 'email',
|
||||
TELEGRAM: 'telegram'
|
||||
};
|
||||
|
||||
// Каналы сообщений
|
||||
const MESSAGE_CHANNELS = {
|
||||
WEB: 'web',
|
||||
TELEGRAM: 'telegram',
|
||||
EMAIL: 'email'
|
||||
};
|
||||
|
||||
// Типы отправителей сообщений
|
||||
const SENDER_TYPES = {
|
||||
USER: 'user',
|
||||
AI: 'ai',
|
||||
ADMIN: 'admin'
|
||||
};
|
||||
|
||||
// Коды ошибок
|
||||
const ERROR_CODES = {
|
||||
UNAUTHORIZED: 'unauthorized',
|
||||
FORBIDDEN: 'forbidden',
|
||||
NOT_FOUND: 'not_found',
|
||||
INTERNAL_ERROR: 'internal_error',
|
||||
BAD_REQUEST: 'bad_request'
|
||||
};
|
||||
|
||||
// Настройки сессии
|
||||
const SESSION_CONFIG = {
|
||||
COOKIE_MAX_AGE: 24 * 60 * 60 * 1000, // 24 часа
|
||||
COOKIE_SECURE: process.env.NODE_ENV === 'production',
|
||||
COOKIE_SAME_SITE: 'lax'
|
||||
};
|
||||
|
||||
// Настройки API
|
||||
const API_CONFIG = {
|
||||
RATE_LIMIT: 100, // запросов в минуту
|
||||
TIMEOUT: 30000 // 30 секунд
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
USER_ROLES,
|
||||
IDENTITY_TYPES,
|
||||
MESSAGE_CHANNELS,
|
||||
SENDER_TYPES,
|
||||
ERROR_CODES,
|
||||
SESSION_CONFIG,
|
||||
API_CONFIG
|
||||
};
|
||||
@@ -3,36 +3,99 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
const logger = require('./logger');
|
||||
|
||||
// Инициализация провайдера
|
||||
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
|
||||
|
||||
// Путь к директории с ABI контрактов
|
||||
const contractsDir = path.join(__dirname, '../artifacts/contracts/AccessToken.sol');
|
||||
|
||||
// Получение ABI контракта
|
||||
const accessTokenJSON = require('../artifacts/contracts/AccessToken.sol/AccessToken.json');
|
||||
const accessTokenABI = accessTokenJSON.abi;
|
||||
|
||||
// Проверка, что ABI является массивом
|
||||
if (!Array.isArray(accessTokenABI)) {
|
||||
console.error('ABI is not an array:', accessTokenABI);
|
||||
// Если ABI не является массивом, создайте массив вручную
|
||||
const manualABI = [
|
||||
"function mintAccessToken(address to, uint8 role) public",
|
||||
"function checkRole(address user) public view returns (uint8)",
|
||||
"function revokeToken(uint256 tokenId) public",
|
||||
// Добавьте другие функции, которые вам нужны
|
||||
];
|
||||
|
||||
// Создание экземпляра контракта с ручным ABI
|
||||
const contractAddress = process.env.ACCESS_TOKEN_ADDRESS;
|
||||
const accessTokenContract = new ethers.Contract(contractAddress, manualABI, provider);
|
||||
|
||||
module.exports = {
|
||||
accessTokenContract,
|
||||
getContract,
|
||||
provider
|
||||
};
|
||||
} else {
|
||||
// Если ABI является массивом, используйте его
|
||||
const contractAddress = process.env.ACCESS_TOKEN_ADDRESS;
|
||||
const accessTokenContract = new ethers.Contract(contractAddress, accessTokenABI, provider);
|
||||
|
||||
module.exports = {
|
||||
accessTokenContract,
|
||||
getContract,
|
||||
provider
|
||||
};
|
||||
}
|
||||
|
||||
// Кэш для хранения экземпляров контрактов
|
||||
const contractsCache = {};
|
||||
|
||||
/**
|
||||
* Получает экземпляр контракта по его имени
|
||||
* @param {string} contractName - Имя контракта (например, 'AccessToken')
|
||||
* @param {string} contractName - Имя контракта
|
||||
* @returns {Promise<ethers.Contract>} - Экземпляр контракта
|
||||
*/
|
||||
async function getContract(contractName) {
|
||||
try {
|
||||
// Путь к артефакту контракта
|
||||
const artifactPath = path.join(__dirname, '..', 'artifacts', 'contracts', `${contractName}.sol`, `${contractName}.json`);
|
||||
console.log(`Getting contract: ${contractName}`);
|
||||
|
||||
// Проверка существования файла
|
||||
if (!fs.existsSync(artifactPath)) {
|
||||
throw new Error(`Артефакт контракта ${contractName} не найден по пути ${artifactPath}`);
|
||||
// Проверяем, есть ли контракт в кэше
|
||||
if (contractsCache[contractName]) {
|
||||
console.log(`Using cached contract: ${contractName}`);
|
||||
return contractsCache[contractName];
|
||||
}
|
||||
|
||||
// Загрузка ABI из артефакта
|
||||
const contractArtifact = require(artifactPath);
|
||||
const contractABI = contractArtifact.abi;
|
||||
// Получаем адрес контракта из переменных окружения
|
||||
const contractAddress = process.env.ACCESS_TOKEN_ADDRESS; // или ACCESS_TOKEN_CONTRACT_ADDRESS
|
||||
|
||||
// Получение адреса контракта из переменных окружения
|
||||
const contractAddress = process.env[`${contractName.toUpperCase()}_ADDRESS`];
|
||||
if (!contractAddress) {
|
||||
throw new Error(`Адрес контракта ${contractName} не найден в переменных окружения`);
|
||||
throw new Error(`Contract address for ${contractName} not found in environment variables`);
|
||||
}
|
||||
|
||||
// Подключение к провайдеру
|
||||
const provider = new ethers.JsonRpcProvider(process.env.ETHEREUM_NETWORK_URL);
|
||||
// Путь к файлу с ABI контракта
|
||||
const abiPath = path.join(contractsDir, `${contractName}.json`);
|
||||
|
||||
// Создание экземпляра контракта
|
||||
const contract = new ethers.Contract(contractAddress, contractABI, provider);
|
||||
// Проверяем, существует ли файл с ABI
|
||||
if (!fs.existsSync(abiPath)) {
|
||||
throw new Error(`ABI file for ${contractName} not found at ${abiPath}`);
|
||||
}
|
||||
|
||||
// Читаем ABI из файла
|
||||
const abiJson = fs.readFileSync(abiPath, 'utf8');
|
||||
const contractJSON = JSON.parse(abiJson);
|
||||
const abi = contractJSON.abi; // Получаем ABI из свойства abi
|
||||
|
||||
console.log(`ABI for ${contractName}:`, abi);
|
||||
|
||||
// Проверяем, что ABI является массивом
|
||||
if (!Array.isArray(abi)) {
|
||||
console.error(`ABI for ${contractName} is not an array:`, abi);
|
||||
throw new Error(`ABI for ${contractName} is not an array`);
|
||||
}
|
||||
|
||||
// Создаем экземпляр контракта
|
||||
const contract = new ethers.Contract(contractAddress, abi, provider);
|
||||
|
||||
// Сохраняем контракт в кэше
|
||||
contractsCache[contractName] = contract;
|
||||
|
||||
return contract;
|
||||
} catch (error) {
|
||||
@@ -40,7 +103,3 @@ async function getContract(contractName) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getContract
|
||||
};
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
// Реэкспорт основного модуля db
|
||||
module.exports = require('../db');
|
||||
@@ -1,10 +1,5 @@
|
||||
const { Pool } = require('pg');
|
||||
|
||||
// Подключение к БД
|
||||
const pool = new Pool({
|
||||
connectionString: process.env.DATABASE_URL,
|
||||
ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
|
||||
});
|
||||
const db = require('../db');
|
||||
const logger = require('./logger');
|
||||
|
||||
/**
|
||||
* Связывает идентификатор с пользователем
|
||||
@@ -16,7 +11,7 @@ const pool = new Pool({
|
||||
async function linkIdentity(userId, identityType, identityValue) {
|
||||
try {
|
||||
// Проверяем, существует ли уже такой идентификатор
|
||||
const existingResult = await pool.query(
|
||||
const existingResult = await db.query(
|
||||
'SELECT * FROM user_identities WHERE identity_type = $1 AND identity_value = $2',
|
||||
[identityType, identityValue]
|
||||
);
|
||||
@@ -32,7 +27,7 @@ async function linkIdentity(userId, identityType, identityValue) {
|
||||
}
|
||||
|
||||
// Добавляем новую связь
|
||||
await pool.query(
|
||||
await db.query(
|
||||
'INSERT INTO user_identities (user_id, identity_type, identity_value, created_at) VALUES ($1, $2, $3, NOW())',
|
||||
[userId, identityType, identityValue]
|
||||
);
|
||||
@@ -53,7 +48,7 @@ async function linkIdentity(userId, identityType, identityValue) {
|
||||
*/
|
||||
async function getUserIdByIdentity(identityType, identityValue) {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
const result = await db.query(
|
||||
'SELECT user_id FROM user_identities WHERE identity_type = $1 AND identity_value = $2',
|
||||
[identityType, identityValue]
|
||||
);
|
||||
@@ -76,7 +71,7 @@ async function getUserIdByIdentity(identityType, identityValue) {
|
||||
*/
|
||||
async function getUserIdentities(userId) {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
const result = await db.query(
|
||||
'SELECT identity_type, identity_value FROM user_identities WHERE user_id = $1',
|
||||
[userId]
|
||||
);
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
import { ethers } from 'ethers';
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(process.env.ETHEREUM_NETWORK_URL);
|
||||
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
|
||||
Reference in New Issue
Block a user