refactor(arch): Phase 2 — deduplicate isAdmin, convertToUsd, getBaseWalletType

- #54: Extract isAdmin() to src/middleware/auth.js, remove duplicates from 7 admin handlers
- #55: Add WalletUtils.convertToUsd(), replace 8 switch-case blocks across 4 files
- #56: Unify getBaseWalletType() — keep only WalletUtils version (most complete),
  remove duplicates from Wallet.js and userWalletsHandler.js

New file: src/middleware/auth.js
Net: -215 lines, +80 lines

Closes: #54, #55, #56
This commit is contained in:
NW
2026-06-17 22:10:34 +01:00
parent de415633be
commit 68d83807ad
13 changed files with 80 additions and 215 deletions

View File

@@ -1,4 +1,4 @@
import config from '../../config/config.js'; import { isAdmin } from '../../middleware/auth.js';
import fs from "fs"; import fs from "fs";
import db from "../../config/database.js"; import db from "../../config/database.js";
import archiver from "archiver"; import archiver from "archiver";
@@ -7,14 +7,11 @@ import bot from "../../context/bot.js";
import userStates from "../../context/userStates.js"; import userStates from "../../context/userStates.js";
export default class AdminDumpHandler { export default class AdminDumpHandler {
static isAdmin(userId) {
return config.ADMIN_IDS.includes(userId.toString());
}
static async handleDump(msg) { static async handleDump(msg) {
const chatId = msg.chat.id; const chatId = msg.chat.id;
if (!this.isAdmin(msg.from.id)) { if (!isAdmin(msg.from.id)) {
await bot.sendMessage(chatId, 'Unauthorized access.'); await bot.sendMessage(chatId, 'Unauthorized access.');
return; return;
} }
@@ -33,7 +30,7 @@ export default class AdminDumpHandler {
} }
static async handleExportDatabase(callbackQuery) { static async handleExportDatabase(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -81,7 +78,7 @@ export default class AdminDumpHandler {
} }
static async handleImportDatabase(callbackQuery) { static async handleImportDatabase(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -130,7 +127,7 @@ export default class AdminDumpHandler {
return false; return false;
} }
if (!this.isAdmin(msg.from.id)) { if (!isAdmin(msg.from.id)) {
await bot.sendMessage(chatId, 'Unauthorized access.'); await bot.sendMessage(chatId, 'Unauthorized access.');
return; return;
} }
@@ -156,7 +153,7 @@ export default class AdminDumpHandler {
} }
static async confirmImport(callbackQuery) { static async confirmImport(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
} }

View File

@@ -1,15 +1,11 @@
import config from '../../config/config.js'; import { isAdmin } from '../../middleware/auth.js';
import bot from "../../context/bot.js"; import bot from "../../context/bot.js";
export default class AdminHandler { export default class AdminHandler {
static isAdmin(userId) {
return config.ADMIN_IDS.includes(userId.toString());
}
static async handleAdminCommand(msg) { static async handleAdminCommand(msg) {
const chatId = msg.chat.id; const chatId = msg.chat.id;
if (!this.isAdmin(msg.from.id)) { if (!isAdmin(msg.from.id)) {
await bot.sendMessage(chatId, 'Unauthorized access.'); await bot.sendMessage(chatId, 'Unauthorized access.');
return; return;
} }

View File

@@ -1,16 +1,13 @@
import db from '../../config/database.js'; import db from '../../config/database.js';
import Validators from '../../utils/validators.js'; import Validators from '../../utils/validators.js';
import config from '../../config/config.js'; import { isAdmin } from '../../middleware/auth.js';
import userStates from "../../context/userStates.js"; import userStates from "../../context/userStates.js";
import bot from "../../context/bot.js"; import bot from "../../context/bot.js";
export default class AdminLocationHandler { export default class AdminLocationHandler {
static isAdmin(userId) {
return config.ADMIN_IDS.includes(userId.toString());
}
static async handleAddLocation(callbackQuery) { static async handleAddLocation(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -38,7 +35,7 @@ export default class AdminLocationHandler {
return false; return false;
} }
if (!this.isAdmin(msg.from.id)) { if (!isAdmin(msg.from.id)) {
await bot.sendMessage(chatId, 'Unauthorized access.'); await bot.sendMessage(chatId, 'Unauthorized access.');
return; return;
} }
@@ -126,7 +123,7 @@ export default class AdminLocationHandler {
static async handleViewIP(callbackQuery) { static async handleViewIP(callbackQuery) {
// Проверка прав администратора // Проверка прав администратора
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -163,7 +160,7 @@ export default class AdminLocationHandler {
const chatId = msg.chat?.id || msg.message?.chat.id; const chatId = msg.chat?.id || msg.message?.chat.id;
const messageId = msg.message?.message_id; const messageId = msg.message?.message_id;
if (!this.isAdmin(msg.from?.id || msg.message?.from.id)) { if (!isAdmin(msg.from?.id || msg.message?.from.id)) {
await bot.sendMessage(chatId, 'Unauthorized access.'); await bot.sendMessage(chatId, 'Unauthorized access.');
return; return;
} }
@@ -241,7 +238,7 @@ export default class AdminLocationHandler {
} }
static async handleDeleteLocation(callbackQuery) { static async handleDeleteLocation(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -284,7 +281,7 @@ export default class AdminLocationHandler {
} }
static async handleConfirmDelete(callbackQuery) { static async handleConfirmDelete(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -337,7 +334,7 @@ export default class AdminLocationHandler {
} }
static async backToMenu(callbackQuery) { static async backToMenu(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }

View File

@@ -1,5 +1,5 @@
import db from '../../config/database.js'; import db from '../../config/database.js';
import config from '../../config/config.js'; import { isAdmin } from '../../middleware/auth.js';
import fs from 'fs/promises'; import fs from 'fs/promises';
import LocationService from "../../services/locationService.js"; import LocationService from "../../services/locationService.js";
import bot from "../../context/bot.js"; import bot from "../../context/bot.js";
@@ -9,14 +9,11 @@ import ProductService from "../../services/productService.js";
import Validators from '../../utils/validators.js'; import Validators from '../../utils/validators.js';
export default class AdminProductHandler { export default class AdminProductHandler {
static isAdmin(userId) {
return config.ADMIN_IDS.includes(userId.toString());
}
static async handleProductManagement(msg) { static async handleProductManagement(msg) {
const chatId = msg.chat?.id || msg.message?.chat.id; const chatId = msg.chat?.id || msg.message?.chat.id;
if (!this.isAdmin(msg.from?.id || msg.message?.from.id)) { if (!isAdmin(msg.from?.id || msg.message?.from.id)) {
await bot.sendMessage(chatId, 'Unauthorized access.'); await bot.sendMessage(chatId, 'Unauthorized access.');
return; return;
} }
@@ -58,7 +55,7 @@ export default class AdminProductHandler {
} }
static async handleCountrySelection(callbackQuery) { static async handleCountrySelection(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -94,7 +91,7 @@ export default class AdminProductHandler {
} }
static async handleCitySelection(callbackQuery) { static async handleCitySelection(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -130,7 +127,7 @@ export default class AdminProductHandler {
} }
static async handleDistrictSelection(callbackQuery) { static async handleDistrictSelection(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -182,7 +179,7 @@ export default class AdminProductHandler {
return false; return false;
} }
if (!this.isAdmin(msg.from.id)) { if (!isAdmin(msg.from.id)) {
await bot.sendMessage(chatId, 'Unauthorized access.'); await bot.sendMessage(chatId, 'Unauthorized access.');
return; return;
} }
@@ -231,7 +228,7 @@ export default class AdminProductHandler {
} }
static async handleAddCategory(callbackQuery) { static async handleAddCategory(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -265,7 +262,7 @@ export default class AdminProductHandler {
return false; return false;
} }
if (!this.isAdmin(msg.from.id)) { if (!isAdmin(msg.from.id)) {
await bot.sendMessage(chatId, 'Неавторизованный доступ.'); await bot.sendMessage(chatId, 'Неавторизованный доступ.');
return; return;
} }
@@ -312,7 +309,7 @@ export default class AdminProductHandler {
} }
// Редактирование категории // Редактирование категории
static async handleEditCategory(callbackQuery) { static async handleEditCategory(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -335,7 +332,7 @@ export default class AdminProductHandler {
); );
} }
static async handleCategorySelection(callbackQuery) { static async handleCategorySelection(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -383,7 +380,7 @@ export default class AdminProductHandler {
return false; return false;
} }
if (!this.isAdmin(msg.from.id)) { if (!isAdmin(msg.from.id)) {
await bot.sendMessage(chatId, 'Unauthorized access.'); await bot.sendMessage(chatId, 'Unauthorized access.');
return; return;
} }
@@ -430,7 +427,7 @@ export default class AdminProductHandler {
} }
static async handleAddSubcategory(callbackQuery) { static async handleAddSubcategory(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -532,7 +529,7 @@ export default class AdminProductHandler {
} }
static async handleCategorySelection(callbackQuery) { static async handleCategorySelection(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -573,7 +570,7 @@ export default class AdminProductHandler {
} }
static async handleProductListPage(callbackQuery) { static async handleProductListPage(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -595,7 +592,7 @@ export default class AdminProductHandler {
} }
static async handleAddProduct(callbackQuery) { static async handleAddProduct(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -654,7 +651,7 @@ export default class AdminProductHandler {
return false; return false;
} }
if (!this.isAdmin(msg.from.id)) { if (!isAdmin(msg.from.id)) {
await bot.sendMessage(chatId, 'Unauthorized access.'); await bot.sendMessage(chatId, 'Unauthorized access.');
return; return;
} }
@@ -762,7 +759,7 @@ export default class AdminProductHandler {
return false; return false;
} }
if (!this.isAdmin(msg.from.id)) { if (!isAdmin(msg.from.id)) {
await bot.sendMessage(chatId, 'Unauthorized access.'); await bot.sendMessage(chatId, 'Unauthorized access.');
return; return;
} }
@@ -863,7 +860,7 @@ export default class AdminProductHandler {
} }
static async handleViewProduct(callbackQuery) { static async handleViewProduct(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -945,7 +942,7 @@ export default class AdminProductHandler {
} }
static async handleProductEdit(callbackQuery) { static async handleProductEdit(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -1005,7 +1002,7 @@ export default class AdminProductHandler {
} }
static async handleProductDelete(callbackQuery) { static async handleProductDelete(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -1047,7 +1044,7 @@ export default class AdminProductHandler {
} }
static async handleConfirmDelete(callbackQuery) { static async handleConfirmDelete(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }

View File

@@ -1,6 +1,6 @@
// adminUserHandler.js // adminUserHandler.js
import config from '../../config/config.js'; import { isAdmin } from '../../middleware/auth.js';
import db from '../../config/database.js'; import db from '../../config/database.js';
import bot from "../../context/bot.js"; import bot from "../../context/bot.js";
import UserService from "../../services/userService.js"; import UserService from "../../services/userService.js";
@@ -10,9 +10,6 @@ import userStates from "../../context/userStates.js";
import Validators from '../../utils/validators.js'; import Validators from '../../utils/validators.js';
export default class AdminUserHandler { export default class AdminUserHandler {
static isAdmin(userId) {
return config.ADMIN_IDS.includes(userId.toString());
}
static async calculateStatistics() { static async calculateStatistics() {
try { try {
@@ -156,7 +153,7 @@ export default class AdminUserHandler {
} }
static async handleUserList(msg) { static async handleUserList(msg) {
if (!this.isAdmin(msg.from.id)) { if (!isAdmin(msg.from.id)) {
await bot.sendMessage(msg.chat.id, 'Unauthorized access.'); await bot.sendMessage(msg.chat.id, 'Unauthorized access.');
return; return;
} }
@@ -166,7 +163,7 @@ export default class AdminUserHandler {
} }
static async handleUserListPage(callbackQuery) { static async handleUserListPage(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -187,7 +184,7 @@ export default class AdminUserHandler {
} }
static async handleViewUser(callbackQuery) { static async handleViewUser(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) return; if (!isAdmin(callbackQuery.from.id)) return;
const telegramId = callbackQuery.data.replace('view_user_', ''); const telegramId = callbackQuery.data.replace('view_user_', '');
const chatId = callbackQuery.message.chat.id; const chatId = callbackQuery.message.chat.id;
@@ -288,7 +285,7 @@ export default class AdminUserHandler {
} }
static async handleDeleteUser(callbackQuery) { static async handleDeleteUser(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -321,7 +318,7 @@ export default class AdminUserHandler {
} }
static async handleConfirmDelete(callbackQuery) { static async handleConfirmDelete(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -358,7 +355,7 @@ export default class AdminUserHandler {
} }
static async handleBlockUser(callbackQuery) { static async handleBlockUser(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -391,7 +388,7 @@ export default class AdminUserHandler {
} }
static async handleConfirmBlock(callbackQuery) { static async handleConfirmBlock(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -428,7 +425,7 @@ export default class AdminUserHandler {
} }
static async handleEditUserBalance(callbackQuery) { static async handleEditUserBalance(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -459,7 +456,7 @@ export default class AdminUserHandler {
} }
static async handleBonusBalanceInput(msg) { static async handleBonusBalanceInput(msg) {
if (!this.isAdmin(msg.from.id)) { if (!isAdmin(msg.from.id)) {
return; return;
} }

View File

@@ -1,16 +1,13 @@
import db from '../../config/database.js'; import db from '../../config/database.js';
import config from "../../config/config.js"; import { isAdmin } from '../../middleware/auth.js';
import LocationService from "../../services/locationService.js"; import LocationService from "../../services/locationService.js";
import bot from "../../context/bot.js"; import bot from "../../context/bot.js";
import UserService from "../../services/userService.js"; import UserService from "../../services/userService.js";
export default class AdminUserLocationHandler { export default class AdminUserLocationHandler {
static isAdmin(userId) {
return config.ADMIN_IDS.includes(userId.toString());
}
static async handleEditUserLocation(callbackQuery) { static async handleEditUserLocation(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -62,7 +59,7 @@ export default class AdminUserLocationHandler {
} }
static async handleEditUserCountry(callbackQuery) { static async handleEditUserCountry(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -98,7 +95,7 @@ export default class AdminUserLocationHandler {
} }
static async handleEditUserCity(callbackQuery) { static async handleEditUserCity(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }
@@ -134,7 +131,7 @@ export default class AdminUserLocationHandler {
} }
static async handleEditUserDistrict(callbackQuery) { static async handleEditUserDistrict(callbackQuery) {
if (!this.isAdmin(callbackQuery.from.id)) { if (!isAdmin(callbackQuery.from.id)) {
return; return;
} }

View File

@@ -8,6 +8,7 @@ const csvPath = path.join(os.tmpdir(), 'wallets_export.csv');
import bot from "../../context/bot.js"; import bot from "../../context/bot.js";
import config from '../../config/config.js'; import config from '../../config/config.js';
import { isAdmin } from '../../middleware/auth.js';
import WalletService from '../../services/walletService.js'; import WalletService from '../../services/walletService.js';
import WalletUtils from '../../utils/walletUtils.js'; import WalletUtils from '../../utils/walletUtils.js';
import Validators from '../../utils/validators.js'; import Validators from '../../utils/validators.js';
@@ -36,15 +37,13 @@ export default class AdminWalletsHandler {
} }
// Метод для проверки, является ли пользователь администратором // Метод для проверки, является ли пользователь администратором
static isAdmin(userId) { // (используется общая функция из middleware/auth.js)
return config.ADMIN_IDS.includes(userId.toString());
}
static async handleWalletManagement(msg) { static async handleWalletManagement(msg) {
const chatId = msg.chat.id; const chatId = msg.chat.id;
// Проверяем, является ли пользователь администратором // Проверяем, является ли пользователь администратором
if (!this.isAdmin(msg.from.id)) { if (!isAdmin(msg.from.id)) {
await bot.sendMessage(chatId, 'Unauthorized access.'); await bot.sendMessage(chatId, 'Unauthorized access.');
return; return;
} }
@@ -133,24 +132,7 @@ export default class AdminWalletsHandler {
const balance = wallet.balance || 0; const balance = wallet.balance || 0;
// Рассчитываем значение в долларах // Рассчитываем значение в долларах
let usdValue = 0; const usdValue = WalletUtils.convertToUsd(wallet.wallet_type, balance, prices);
switch (baseType) {
case 'BTC':
usdValue = balance * prices.btc;
break;
case 'LTC':
usdValue = balance * prices.ltc;
break;
case 'ETH':
usdValue = balance * prices.eth;
break;
case 'USDT':
usdValue = balance; // USDT привязан к доллару
break;
case 'USDC':
usdValue = balance; // USDC привязан к доллару
break;
}
// Формируем строку для кошелька // Формируем строку для кошелька
walletList += `💰 ${baseType}${archivedDate}\n`; walletList += `💰 ${baseType}${archivedDate}\n`;
@@ -208,24 +190,7 @@ export default class AdminWalletsHandler {
const balance = wallet.balance || 0; const balance = wallet.balance || 0;
// Рассчитываем значение в долларах // Рассчитываем значение в долларах
let usdValue = 0; const usdValue = WalletUtils.convertToUsd(wallet.wallet_type, balance, prices);
switch (baseType) {
case 'BTC':
usdValue = balance * prices.btc;
break;
case 'LTC':
usdValue = balance * prices.ltc;
break;
case 'ETH':
usdValue = balance * prices.eth;
break;
case 'USDT':
usdValue = balance; // USDT привязан к доллару
break;
case 'USDC':
usdValue = balance; // USDC привязан к доллару
break;
}
totalBalance += usdValue; totalBalance += usdValue;
} }
@@ -429,24 +394,7 @@ export default class AdminWalletsHandler {
const balance = wallet.balance || 0; const balance = wallet.balance || 0;
// Рассчитываем значение в долларах // Рассчитываем значение в долларах
let usdValue = 0; const usdValue = WalletUtils.convertToUsd(wallet.wallet_type, balance, prices);
switch (baseType) {
case 'BTC':
usdValue = balance * prices.btc;
break;
case 'LTC':
usdValue = balance * prices.ltc;
break;
case 'ETH':
usdValue = balance * prices.eth;
break;
case 'USDT':
usdValue = balance; // USDT привязан к доллару
break;
case 'USDC':
usdValue = balance; // USDC привязан к доллару
break;
}
// Форматируем дату архивации (если кошелек архивный) // Форматируем дату архивации (если кошелек архивный)
let archivedDate = ''; let archivedDate = '';

View File

@@ -728,11 +728,6 @@ export default class UserWalletsHandler {
} }
// Helper methods // Helper methods
static getBaseWalletType(walletType) {
if (walletType.includes('ERC-20')) return 'ETH';
return walletType;
}
static getWalletAddress(wallets, walletType) { static getWalletAddress(wallets, walletType) {
if (walletType.includes('ERC-20')) return wallets.ETH.address; if (walletType.includes('ERC-20')) return wallets.ETH.address;
if (walletType === 'BTC') return wallets.BTC.address; if (walletType === 'BTC') return wallets.BTC.address;
@@ -749,9 +744,4 @@ export default class UserWalletsHandler {
if (walletType === 'ETH') return 'Ethereum Network'; if (walletType === 'ETH') return 'Ethereum Network';
return 'Unknown Network'; return 'Unknown Network';
} }
static getBaseWalletType(walletType) {
// Убираем суффиксы, такие как ERC-20, TRC-20 и т.д.
return walletType.replace(/ (ERC-20|TRC-20)$/, '');
}
} }

5
src/middleware/auth.js Normal file
View File

@@ -0,0 +1,5 @@
import config from '../config/config.js';
export function isAdmin(userId) {
return config.ADMIN_IDS.includes(userId.toString());
}

View File

@@ -4,11 +4,6 @@ import db from "../config/database.js";
import WalletUtils from "../utils/walletUtils.js"; import WalletUtils from "../utils/walletUtils.js";
export default class Wallet { export default class Wallet {
static getBaseWalletType(walletType) {
if (walletType.includes('ERC-20')) return 'ETH';
return walletType;
}
static async getArchivedWallets(userId) { static async getArchivedWallets(userId) {
const archivedWallets = await db.allAsync(` const archivedWallets = await db.allAsync(`
SELECT * FROM crypto_wallets WHERE user_id = ? AND wallet_type LIKE '%_%' SELECT * FROM crypto_wallets WHERE user_id = ? AND wallet_type LIKE '%_%'
@@ -60,7 +55,7 @@ export default class Wallet {
let totalUsdBalance = 0; let totalUsdBalance = 0;
for (const [type, balance] of Object.entries(balances)) { for (const [type, balance] of Object.entries(balances)) {
const baseType = this.getBaseWalletType(type); const baseType = WalletUtils.getBaseWalletType(type);
const wallet = activeWallets.wallets.find(w => const wallet = activeWallets.wallets.find(w =>
w.wallet_type === baseType || w.wallet_type === baseType ||
(type.includes('ERC-20') && w.wallet_type === 'ETH') (type.includes('ERC-20') && w.wallet_type === 'ETH')
@@ -92,7 +87,7 @@ export default class Wallet {
let totalUsdBalance = 0; let totalUsdBalance = 0;
for (const [type, balance] of Object.entries(balances)) { for (const [type, balance] of Object.entries(balances)) {
const baseType = this.getBaseWalletType(type); const baseType = WalletUtils.getBaseWalletType(type);
const wallet = archiveWallets.wallets.find(w => const wallet = archiveWallets.wallets.find(w =>
w.wallet_type === baseType || w.wallet_type === baseType ||
(type.includes('ERC-20') && w.wallet_type.startsWith('ETH')) (type.includes('ERC-20') && w.wallet_type.startsWith('ETH'))

View File

@@ -150,9 +150,7 @@ class UserService {
// Пересчитываем балансы в доллары // Пересчитываем балансы в доллары
let totalCryptoBalance = 0; let totalCryptoBalance = 0;
for (const wallet of cryptoBalances) { for (const wallet of cryptoBalances) {
const baseType = WalletUtils.getBaseWalletType(wallet.wallet_type); // Убираем суффиксы totalCryptoBalance += WalletUtils.convertToUsd(wallet.wallet_type, wallet.balance, prices);
const rate = prices[baseType.toLowerCase()] || 0; // Получаем курс для базового типа
totalCryptoBalance += wallet.balance * rate;
} }
// Получаем сумму всех покупок в крипте // Получаем сумму всех покупок в крипте

View File

@@ -35,26 +35,8 @@ class WalletService {
let totalBalance = 0; let totalBalance = 0;
for (const wallet of wallets) { for (const wallet of wallets) {
const baseType = WalletUtils.getBaseWalletType(wallet.wallet_type);
const balance = wallet.balance || 0; const balance = wallet.balance || 0;
totalBalance += WalletUtils.convertToUsd(wallet.wallet_type, balance, prices);
switch (baseType) {
case 'BTC':
totalBalance += balance * prices.btc;
break;
case 'LTC':
totalBalance += balance * prices.ltc;
break;
case 'ETH':
totalBalance += balance * prices.eth;
break;
case 'USDT':
totalBalance += balance; // USDT is 1:1 with USD
break;
case 'USDC':
totalBalance += balance; // USDC is 1:1 with USD
break;
}
} }
return totalBalance; return totalBalance;
@@ -77,26 +59,8 @@ class WalletService {
let totalBalance = 0; let totalBalance = 0;
for (const wallet of wallets) { for (const wallet of wallets) {
const baseType = WalletUtils.getBaseWalletType(wallet.wallet_type);
const balance = wallet.balance || 0; const balance = wallet.balance || 0;
totalBalance += WalletUtils.convertToUsd(wallet.wallet_type, balance, prices);
switch (baseType) {
case 'BTC':
totalBalance += balance * prices.btc;
break;
case 'LTC':
totalBalance += balance * prices.ltc;
break;
case 'ETH':
totalBalance += balance * prices.eth;
break;
case 'USDT':
totalBalance += balance; // USDT is 1:1 with USD
break;
case 'USDC':
totalBalance += balance; // USDC is 1:1 with USD
break;
}
} }
return totalBalance; return totalBalance;

View File

@@ -76,20 +76,21 @@ export default class WalletUtils {
} }
static getBaseWalletType(walletType) { static getBaseWalletType(walletType) {
// Убираем суффикс ERC-20, если он есть
if (walletType.includes('ERC-20')) { if (walletType.includes('ERC-20')) {
return 'ETH'; return 'ETH';
} }
// Убираем суффикс с таймштампом (например, USDT_1735846098129 -> USDT)
if (walletType.includes('_')) { if (walletType.includes('_')) {
return walletType.split('_')[0]; return walletType.split('_')[0];
} }
// Возвращаем исходный тип, если это не ERC-20 и не архивный кошелек
return walletType; return walletType;
} }
static convertToUsd(walletType, balance, prices) {
const baseType = WalletUtils.getBaseWalletType(walletType);
const rate = prices[baseType.toLowerCase()] || 0;
return balance * rate;
}
static async getCryptoPrices() { static async getCryptoPrices() {
// Если кеш актуален, возвращаем его // Если кеш актуален, возвращаем его
if (cryptoPricesCache && Date.now() - cacheTimestamp < CACHE_TTL) { if (cryptoPricesCache && Date.now() - cacheTimestamp < CACHE_TTL) {
@@ -291,30 +292,13 @@ export default class WalletUtils {
`, [this.userId]); `, [this.userId]);
for (const wallet of wallets) { for (const wallet of wallets) {
const [baseType] = wallet.wallet_type.split('_'); // Учитываем только базовый тип const baseType = WalletUtils.getBaseWalletType(wallet.wallet_type);
const balance = wallet.balance || 0; const balance = wallet.balance || 0;
const usdValue = WalletUtils.convertToUsd(wallet.wallet_type, balance, prices);
switch (baseType) {
case 'BTC': if (balances[baseType]) {
balances.BTC.amount += balance; balances[baseType].amount += balance;
balances.BTC.usdValue += balance * prices.btc; balances[baseType].usdValue += usdValue;
break;
case 'LTC':
balances.LTC.amount += balance;
balances.LTC.usdValue += balance * prices.ltc;
break;
case 'ETH':
balances.ETH.amount += balance;
balances.ETH.usdValue += balance * prices.eth;
break;
case 'USDT':
balances.USDT.amount += balance;
balances.USDT.usdValue += balance;
break;
case 'USDC':
balances.USDC.amount += balance;
balances.USDC.usdValue += balance;
break;
} }
} }