feat: новая функция
This commit is contained in:
@@ -67,7 +67,7 @@ async function checkAdminRole(address) {
|
||||
errorCount++;
|
||||
return null;
|
||||
}
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
const provider = new ethers.JsonRpcProvider(await rpcService.getRpcUrlByChainId(chainId));
|
||||
// Проверяем доступность сети с таймаутом
|
||||
try {
|
||||
const networkCheckPromise = provider.getNetwork();
|
||||
|
||||
@@ -455,6 +455,7 @@ class AuthService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Определяет уровень доступа пользователя на основе количества токенов
|
||||
* @param {string} address - Адрес кошелька
|
||||
@@ -490,23 +491,35 @@ class AuthService {
|
||||
const tokens = tokensResult.rows;
|
||||
|
||||
// Получаем RPC провайдеры
|
||||
const rpcProvidersResult = await db.getQuery()(
|
||||
'SELECT id, chain_id, created_at, updated_at, decrypt_text(network_id_encrypted, $1) as network_id, decrypt_text(rpc_url_encrypted, $1) as rpc_url FROM rpc_providers',
|
||||
[encryptionKey]
|
||||
);
|
||||
const rpcProviders = rpcProvidersResult.rows;
|
||||
// Убрано - используем rpcService вместо прямого запроса к БД
|
||||
|
||||
const rpcMap = {};
|
||||
for (const rpc of rpcProviders) {
|
||||
rpcMap[rpc.network_id] = rpc.rpc_url;
|
||||
}
|
||||
// Используем правильный RPC URL из базы данных
|
||||
const rpcService = require('./rpcProviderService');
|
||||
|
||||
// Получаем балансы токенов из блокчейна
|
||||
const ERC20_ABI = ['function balanceOf(address owner) view returns (uint256)'];
|
||||
const tokenBalances = [];
|
||||
|
||||
// Получаем все RPC провайдеры из базы данных для маппинга
|
||||
const allRpcProviders = await rpcService.getAllRpcProviders();
|
||||
const networkToChainId = {};
|
||||
|
||||
// Создаем маппинг из базы данных
|
||||
for (const provider of allRpcProviders) {
|
||||
if (provider.network_id) {
|
||||
networkToChainId[provider.network_id] = provider.chain_id;
|
||||
}
|
||||
}
|
||||
|
||||
for (const token of tokens) {
|
||||
const rpcUrl = rpcMap[token.network];
|
||||
// Получаем chain_id из названия сети из базы данных
|
||||
const chainId = networkToChainId[token.network];
|
||||
if (!chainId) {
|
||||
logger.warn(`[getUserAccessLevel] Неизвестная сеть: ${token.network}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const rpcUrl = await rpcService.getRpcUrlByChainId(chainId);
|
||||
if (!rpcUrl) continue;
|
||||
|
||||
try {
|
||||
|
||||
@@ -565,7 +565,7 @@ class DLEV2Service {
|
||||
* @param {Array} allDles - Все DLE
|
||||
* @returns {Array} - Сгруппированные DLE
|
||||
*/
|
||||
groupMultichainDLEs(allDles) {
|
||||
async groupMultichainDLEs(allDles) {
|
||||
const groups = new Map();
|
||||
|
||||
for (const dle of allDles) {
|
||||
@@ -588,7 +588,7 @@ class DLEV2Service {
|
||||
groups.get(groupKey).networks.push({
|
||||
chainId: dle.chainId,
|
||||
address: dle.address,
|
||||
networkName: this.getRpcUrlForChain(dle.chainId)?.name || `Chain ${dle.chainId}`,
|
||||
networkName: (await this.getRpcUrlForChain(dle.chainId))?.name || `Chain ${dle.chainId}`,
|
||||
status: dle.status || 'active'
|
||||
});
|
||||
}
|
||||
@@ -610,16 +610,25 @@ class DLEV2Service {
|
||||
* @param {number} chainId - ID сети
|
||||
* @returns {Object|null} - Информация о RPC
|
||||
*/
|
||||
getRpcUrlForChain(chainId) {
|
||||
const rpcMappings = {
|
||||
1: { name: 'Ethereum Mainnet', url: 'https://mainnet.infura.io/v3/' },
|
||||
11155111: { name: 'Sepolia Testnet', url: 'https://sepolia.infura.io/v3/' },
|
||||
17000: { name: 'Holesky Testnet', url: 'https://holesky.infura.io/v3/' },
|
||||
421614: { name: 'Arbitrum Sepolia', url: 'https://sepolia-rollup.arbitrum.io/rpc' },
|
||||
84532: { name: 'Base Sepolia', url: 'https://sepolia.base.org' }
|
||||
};
|
||||
|
||||
return rpcMappings[chainId] || null;
|
||||
async getRpcUrlForChain(chainId) {
|
||||
try {
|
||||
// Получаем RPC URL из базы данных
|
||||
const rpcService = require('./rpcProviderService');
|
||||
const rpcUrl = await rpcService.getRpcUrlByChainId(chainId);
|
||||
|
||||
if (!rpcUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Возвращаем объект с RPC URL из базы данных
|
||||
return {
|
||||
name: `Chain ${chainId}`,
|
||||
url: rpcUrl
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`[DLE V2 Service] Ошибка получения RPC для chain_id ${chainId}:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -639,7 +648,7 @@ class DLEV2Service {
|
||||
throw new Error(`RPC URL не найден для сети ${chainId}`);
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
const provider = new ethers.JsonRpcProvider(await getRpcUrlByChainId(chainId));
|
||||
const balance = await provider.getBalance(wallet.address);
|
||||
|
||||
console.log(`💰 Баланс в сети ${chainId}: ${ethers.formatEther(balance)} ETH`);
|
||||
|
||||
@@ -32,26 +32,52 @@ async function getUserTokenBalances(address) {
|
||||
);
|
||||
const tokens = tokensResult.rows;
|
||||
|
||||
const rpcProvidersResult = await db.getQuery()(
|
||||
'SELECT id, chain_id, created_at, updated_at, decrypt_text(network_id_encrypted, $1) as network_id, decrypt_text(rpc_url_encrypted, $1) as rpc_url FROM rpc_providers',
|
||||
[encryptionKey]
|
||||
);
|
||||
const rpcProviders = rpcProvidersResult.rows;
|
||||
const rpcMap = {};
|
||||
for (const rpc of rpcProviders) {
|
||||
rpcMap[rpc.network_id] = rpc.rpc_url;
|
||||
}
|
||||
// Убрано - используем rpcService вместо прямого запроса к БД
|
||||
// Используем правильный RPC URL из базы данных
|
||||
const rpcService = require('./rpcProviderService');
|
||||
|
||||
const ERC20_ABI = ['function balanceOf(address owner) view returns (uint256)'];
|
||||
const results = [];
|
||||
|
||||
// Получаем все RPC провайдеры из базы данных для маппинга
|
||||
const allRpcProviders = await rpcService.getAllRpcProviders();
|
||||
const networkToChainId = {};
|
||||
|
||||
// Создаем маппинг из базы данных
|
||||
for (const provider of allRpcProviders) {
|
||||
if (provider.network_id) {
|
||||
networkToChainId[provider.network_id] = provider.chain_id;
|
||||
}
|
||||
}
|
||||
|
||||
for (const token of tokens) {
|
||||
const rpcUrl = rpcMap[token.network];
|
||||
if (!rpcUrl) {
|
||||
logger.warn(`[tokenBalanceService] RPC URL не найден для сети ${token.network}`);
|
||||
// Получаем chain_id из названия сети из базы данных
|
||||
const chainId = networkToChainId[token.network];
|
||||
if (!chainId) {
|
||||
logger.warn(`[tokenBalanceService] Неизвестная сеть: ${token.network}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
logger.info(`[tokenBalanceService] Ищем RPC для token.network: ${token.network} (chainId: ${chainId})`);
|
||||
const rpcUrl = await rpcService.getRpcUrlByChainId(chainId);
|
||||
if (!rpcUrl) {
|
||||
logger.warn(`[tokenBalanceService] RPC URL не найден для сети ${token.network} (chainId: ${chainId})`);
|
||||
// Пропускаем токен, если нет RPC URL
|
||||
results.push({
|
||||
network: token.network,
|
||||
tokenAddress: token.address,
|
||||
tokenName: token.name,
|
||||
symbol: token.symbol || '',
|
||||
balance: '0',
|
||||
minBalance: token.min_balance,
|
||||
readonlyThreshold: token.readonly_threshold || 1,
|
||||
editorThreshold: token.editor_threshold || 2,
|
||||
error: 'RPC URL не настроен'
|
||||
});
|
||||
continue;
|
||||
}
|
||||
logger.info(`[tokenBalanceService] Найден RPC URL: ${rpcUrl}`);
|
||||
|
||||
// Создаем провайдер с таймаутом
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl, undefined, {
|
||||
polling: false,
|
||||
@@ -84,8 +110,38 @@ async function getUserTokenBalances(address) {
|
||||
`[tokenBalanceService] Ошибка получения баланса для ${token.name} (${token.address}) в сети ${token.network}:`,
|
||||
e.message || e
|
||||
);
|
||||
|
||||
// Проверяем тип ошибки для лучшей диагностики
|
||||
const errorMessage = e.message || e.toString();
|
||||
let errorType = 'Неизвестная ошибка';
|
||||
|
||||
if (errorMessage.includes('timeout') || errorMessage.includes('TIMEOUT')) {
|
||||
errorType = 'Таймаут соединения - возможно, нужен VPN';
|
||||
} else if (errorMessage.includes('ECONNREFUSED') || errorMessage.includes('ENOTFOUND')) {
|
||||
errorType = 'Не удается подключиться к RPC провайдеру';
|
||||
} else if (errorMessage.includes('NETWORK_ERROR')) {
|
||||
errorType = 'Ошибка сети - проверьте интернет-соединение';
|
||||
}
|
||||
|
||||
balance = '0';
|
||||
|
||||
// Добавляем информацию об ошибке в результат
|
||||
results.push({
|
||||
network: token.network,
|
||||
tokenAddress: token.address,
|
||||
tokenName: token.name,
|
||||
symbol: token.symbol || '',
|
||||
balance,
|
||||
minBalance: token.min_balance,
|
||||
readonlyThreshold: token.readonly_threshold || 1,
|
||||
editorThreshold: token.editor_threshold || 2,
|
||||
error: errorType,
|
||||
errorDetails: errorMessage
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
// Добавляем успешный результат
|
||||
results.push({
|
||||
network: token.network,
|
||||
tokenAddress: token.address,
|
||||
@@ -98,7 +154,8 @@ async function getUserTokenBalances(address) {
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
// Преобразуем в обычный массив для корректной сериализации
|
||||
return JSON.parse(JSON.stringify(results));
|
||||
}
|
||||
|
||||
module.exports = { getUserTokenBalances };
|
||||
|
||||
Reference in New Issue
Block a user