separate wallet ETH USDT USDC
This commit is contained in:
parent
22f76c64a6
commit
e64f185eda
@ -13,28 +13,29 @@ export default class AdminWalletsHandler {
|
||||
|
||||
static async handleWalletManagement(msg) {
|
||||
const chatId = msg.chat.id;
|
||||
|
||||
|
||||
// Проверяем, является ли пользователь администратором
|
||||
if (!this.isAdmin(msg.from.id)) {
|
||||
await bot.sendMessage(chatId, 'Unauthorized access.');
|
||||
return;
|
||||
await bot.sendMessage(chatId, 'Unauthorized access.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const keyboard = {
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[
|
||||
{ text: 'Bitcoin (BTC)', callback_data: 'wallet_type_BTC' },
|
||||
{ text: 'Litecoin (LTC)', callback_data: 'wallet_type_LTC' }
|
||||
],
|
||||
[
|
||||
{ text: 'Tether (USDT)', callback_data: 'wallet_type_USDT' },
|
||||
{ text: 'Ethereum (ETH)', callback_data: 'wallet_type_ETH' }
|
||||
]
|
||||
]
|
||||
}
|
||||
reply_markup: {
|
||||
inline_keyboard: [
|
||||
[
|
||||
{ text: 'Bitcoin (BTC)', callback_data: 'wallet_type_BTC' },
|
||||
{ text: 'Litecoin (LTC)', callback_data: 'wallet_type_LTC' }
|
||||
],
|
||||
[
|
||||
{ text: 'Tether (USDT)', callback_data: 'wallet_type_USDT' },
|
||||
{ text: 'USD Coin (USDC)', callback_data: 'wallet_type_USDC' },
|
||||
{ text: 'Ethereum (ETH)', callback_data: 'wallet_type_ETH' }
|
||||
]
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
await bot.sendMessage(chatId, 'Select wallet type:', keyboard);
|
||||
}
|
||||
|
||||
@ -71,27 +72,27 @@ export default class AdminWalletsHandler {
|
||||
const startIndex = page * pageSize;
|
||||
const endIndex = startIndex + pageSize;
|
||||
const walletsPage = wallets.slice(startIndex, endIndex);
|
||||
|
||||
|
||||
// Формируем список кошельков с балансами
|
||||
let walletList = '';
|
||||
for (const wallet of walletsPage) {
|
||||
const walletUtilsInstance = new WalletUtils(
|
||||
wallet.wallet_type.startsWith('BTC') ? wallet.address : null,
|
||||
wallet.wallet_type.startsWith('LTC') ? wallet.address : null,
|
||||
wallet.wallet_type.startsWith('ETH') ? wallet.address : null,
|
||||
wallet.wallet_type === 'BTC' ? wallet.address : null,
|
||||
wallet.wallet_type === 'LTC' ? wallet.address : null,
|
||||
wallet.wallet_type === 'ETH' || wallet.wallet_type === 'USDT' || wallet.wallet_type === 'USDC' ? wallet.address : null,
|
||||
null, // userId не нужен для админки
|
||||
Date.now() - 30 * 24 * 60 * 60 * 1000
|
||||
);
|
||||
|
||||
|
||||
const balances = await walletUtilsInstance.getAllBalances();
|
||||
const balance = balances[wallet.wallet_type] || { amount: 0, usdValue: 0 };
|
||||
|
||||
|
||||
walletList += `💰 *${wallet.wallet_type}*\n`;
|
||||
walletList += `├ Balance: ${balance.amount.toFixed(8)} ${wallet.wallet_type.split(' ')[0]}\n`;
|
||||
walletList += `├ Balance: ${balance.amount.toFixed(8)} ${wallet.wallet_type}\n`;
|
||||
walletList += `├ Value: $${balance.usdValue.toFixed(2)}\n`;
|
||||
walletList += `└ Address: \`${wallet.address}\`\n\n`;
|
||||
}
|
||||
|
||||
|
||||
// Создаем клавиатуру с пагинацией
|
||||
const keyboard = {
|
||||
inline_keyboard: [
|
||||
@ -105,17 +106,17 @@ export default class AdminWalletsHandler {
|
||||
]
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
// Убираем кнопку "Назад", если это первая страница
|
||||
if (page === 0) {
|
||||
keyboard.inline_keyboard[0].shift();
|
||||
}
|
||||
|
||||
|
||||
// Убираем кнопку "Далее", если это последняя страница
|
||||
if (endIndex >= wallets.length) {
|
||||
keyboard.inline_keyboard[0].pop();
|
||||
}
|
||||
|
||||
|
||||
// Отправляем сообщение с суммарным балансом и списком кошельков
|
||||
await bot.sendMessage(
|
||||
chatId,
|
||||
@ -132,9 +133,9 @@ export default class AdminWalletsHandler {
|
||||
|
||||
for (const wallet of wallets) {
|
||||
const walletUtilsInstance = new WalletUtils(
|
||||
wallet.wallet_type.startsWith('BTC') ? wallet.address : null,
|
||||
wallet.wallet_type.startsWith('LTC') ? wallet.address : null,
|
||||
wallet.wallet_type.startsWith('ETH') ? wallet.address : null,
|
||||
wallet.wallet_type === 'BTC' ? wallet.address : null,
|
||||
wallet.wallet_type === 'LTC' ? wallet.address : null,
|
||||
wallet.wallet_type === 'ETH' || wallet.wallet_type === 'USDT' || wallet.wallet_type === 'USDC' ? wallet.address : null,
|
||||
null, // userId не нужен для админки
|
||||
Date.now() - 30 * 24 * 60 * 60 * 1000
|
||||
);
|
||||
@ -150,7 +151,7 @@ export default class AdminWalletsHandler {
|
||||
static async handlePagination(callbackQuery) {
|
||||
const action = callbackQuery.data;
|
||||
const chatId = callbackQuery.message.chat.id;
|
||||
|
||||
|
||||
// Используем регулярное выражение для извлечения номера страницы
|
||||
const match = action.match(/next_page_(.+)_(\d+)/) || action.match(/prev_page_(.+)_(\d+)/);
|
||||
if (!match) {
|
||||
@ -158,20 +159,20 @@ export default class AdminWalletsHandler {
|
||||
await bot.sendMessage(chatId, 'Invalid pagination action. Please try again.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const walletType = match[1]; // Тип кошелька (например, BTC)
|
||||
const pageNumber = parseInt(match[2]); // Номер страницы
|
||||
|
||||
|
||||
try {
|
||||
// Удаляем предыдущее сообщение перед отправкой нового
|
||||
await bot.deleteMessage(chatId, callbackQuery.message.message_id);
|
||||
|
||||
|
||||
// Получаем все кошельки выбранного типа
|
||||
const wallets = await WalletService.getWalletsByType(walletType);
|
||||
|
||||
|
||||
// Вычисляем суммарный баланс
|
||||
const totalBalance = await this.calculateTotalBalance(wallets);
|
||||
|
||||
|
||||
// Отображаем страницу с учетом пагинации
|
||||
await this.displayWalletsPage(chatId, wallets, walletType, totalBalance, pageNumber);
|
||||
} catch (error) {
|
||||
@ -184,47 +185,47 @@ export default class AdminWalletsHandler {
|
||||
const action = callbackQuery.data;
|
||||
const chatId = callbackQuery.message.chat.id;
|
||||
const walletType = action.split('_').pop();
|
||||
|
||||
|
||||
try {
|
||||
// Удаляем предыдущее сообщение перед отправкой нового
|
||||
await bot.deleteMessage(chatId, callbackQuery.message.message_id);
|
||||
|
||||
|
||||
// Получаем все кошельки выбранного типа
|
||||
const wallets = await WalletService.getWalletsByType(walletType);
|
||||
|
||||
|
||||
if (wallets.length === 0) {
|
||||
await bot.sendMessage(chatId, `No wallets found for ${walletType}.`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Расшифровываем мнемоническую фразу и получаем балансы
|
||||
const walletsWithData = await Promise.all(wallets.map(async (wallet) => {
|
||||
if (!wallet.mnemonic) {
|
||||
console.error(`Mnemonic is missing for wallet with ID ${wallet.id}`);
|
||||
return null; // Пропускаем кошелек, если mnemonic отсутствует
|
||||
}
|
||||
|
||||
|
||||
const walletUtilsInstance = new WalletUtils(
|
||||
wallet.wallet_type.startsWith('BTC') ? wallet.address : null,
|
||||
wallet.wallet_type.startsWith('LTC') ? wallet.address : null,
|
||||
wallet.wallet_type.startsWith('ETH') ? wallet.address : null,
|
||||
wallet.wallet_type === 'BTC' ? wallet.address : null,
|
||||
wallet.wallet_type === 'LTC' ? wallet.address : null,
|
||||
wallet.wallet_type === 'ETH' || wallet.wallet_type === 'USDT' || wallet.wallet_type === 'USDC' ? wallet.address : null,
|
||||
null, // userId не нужен для админки
|
||||
Date.now() - 30 * 24 * 60 * 60 * 1000
|
||||
);
|
||||
|
||||
|
||||
const balances = await walletUtilsInstance.getAllBalances();
|
||||
const balance = balances[wallet.wallet_type] || { amount: 0, usdValue: 0 };
|
||||
|
||||
|
||||
return {
|
||||
address: wallet.address,
|
||||
balance: balance.amount.toFixed(8),
|
||||
mnemonic: wallet.mnemonic
|
||||
};
|
||||
}));
|
||||
|
||||
|
||||
// Убираем null значения из массива
|
||||
const filteredWallets = walletsWithData.filter(wallet => wallet !== null);
|
||||
|
||||
|
||||
// Создаем CSV-файл
|
||||
const csv = csvWriter.createObjectCsvWriter({
|
||||
path: `wallets_${walletType}.csv`,
|
||||
@ -234,12 +235,12 @@ export default class AdminWalletsHandler {
|
||||
{ id: 'mnemonic', title: 'Mnemonic' }
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
await csv.writeRecords(filteredWallets);
|
||||
|
||||
|
||||
// Отправляем файл пользователю
|
||||
await bot.sendDocument(chatId, fs.createReadStream(`wallets_${walletType}.csv`));
|
||||
|
||||
|
||||
// Удаляем временный файл
|
||||
fs.unlinkSync(`wallets_${walletType}.csv`);
|
||||
} catch (error) {
|
||||
@ -247,8 +248,7 @@ export default class AdminWalletsHandler {
|
||||
await bot.sendMessage(chatId, 'Failed to export wallets to CSV. Please try again later.');
|
||||
}
|
||||
}
|
||||
|
||||
// Метод для возврата к списку типов кошельков
|
||||
|
||||
static async handleBackToWalletTypes(callbackQuery) {
|
||||
const chatId = callbackQuery.message.chat.id;
|
||||
|
||||
@ -265,6 +265,7 @@ export default class AdminWalletsHandler {
|
||||
],
|
||||
[
|
||||
{ text: 'Tether (USDT)', callback_data: 'wallet_type_USDT' },
|
||||
{ text: 'USD Coin (USDC)', callback_data: 'wallet_type_USDC' },
|
||||
{ text: 'Ethereum (ETH)', callback_data: 'wallet_type_ETH' }
|
||||
]
|
||||
]
|
||||
|
||||
@ -6,102 +6,101 @@ import WalletService from "../../services/walletService.js";
|
||||
import bot from "../../context/bot.js";
|
||||
|
||||
export default class UserWalletsHandler {
|
||||
|
||||
static async showBalance(msg) {
|
||||
const chatId = msg.chat.id;
|
||||
const telegramId = msg.from.id;
|
||||
|
||||
try {
|
||||
const user = await UserService.getUserByTelegramId(telegramId.toString());
|
||||
const user = await UserService.getUserByTelegramId(telegramId.toString());
|
||||
|
||||
if (!user) {
|
||||
await bot.sendMessage(chatId, 'Profile not found. Please use /start to create one.');
|
||||
return;
|
||||
if (!user) {
|
||||
await bot.sendMessage(chatId, 'Profile not found. Please use /start to create one.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Get active crypto wallets only
|
||||
const cryptoWallets = await db.allAsync(`
|
||||
SELECT wallet_type, address
|
||||
FROM crypto_wallets
|
||||
WHERE user_id = ?
|
||||
ORDER BY wallet_type
|
||||
`, [user.id]);
|
||||
|
||||
let message = '💰 *Your Active Wallets:*\n\n';
|
||||
|
||||
if (cryptoWallets.length > 0) {
|
||||
const walletUtilsInstance = new WalletUtils(
|
||||
cryptoWallets.find(w => w.wallet_type === 'BTC')?.address, // BTC address
|
||||
cryptoWallets.find(w => w.wallet_type === 'LTC')?.address, // LTC address
|
||||
cryptoWallets.find(w => w.wallet_type === 'ETH')?.address, // ETH address
|
||||
cryptoWallets.find(w => w.wallet_type === 'USDT')?.address, // USDT address
|
||||
cryptoWallets.find(w => w.wallet_type === 'USDC')?.address, // USDC address
|
||||
user.id,
|
||||
Date.now() - 30 * 24 * 60 * 60 * 1000
|
||||
);
|
||||
|
||||
const balances = await walletUtilsInstance.getAllBalances();
|
||||
let totalUsdValue = 0;
|
||||
|
||||
// Show active wallets
|
||||
for (const [type, balance] of Object.entries(balances)) {
|
||||
const wallet = cryptoWallets.find(w => w.wallet_type === type.split(' ')[0]);
|
||||
|
||||
if (wallet) {
|
||||
message += `🔐 *${type}*\n`;
|
||||
message += `├ Balance: ${balance.amount.toFixed(8)} ${type.split(' ')[0]}\n`;
|
||||
message += `├ Value: $${balance.usdValue.toFixed(2)}\n`;
|
||||
message += `└ Address: \`${wallet.address}\`\n\n`;
|
||||
totalUsdValue += balance.usdValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Get active crypto wallets only
|
||||
const cryptoWallets = await db.allAsync(`
|
||||
SELECT wallet_type, address
|
||||
FROM crypto_wallets
|
||||
WHERE user_id = ?
|
||||
ORDER BY wallet_type
|
||||
`, [user.id]);
|
||||
// Add total crypto balance
|
||||
message += `📊 *Total Crypto Balance:* $${totalUsdValue.toFixed(2)}\n`;
|
||||
|
||||
let message = '💰 *Your Active Wallets:*\n\n';
|
||||
// Add bonus balance
|
||||
message += `🎁 *Bonus Balance:* $${user.bonus_balance.toFixed(2)}\n`;
|
||||
|
||||
if (cryptoWallets.length > 0) {
|
||||
const walletUtilsInstance = new WalletUtils(
|
||||
cryptoWallets.find(w => w.wallet_type === 'BTC')?.address,
|
||||
cryptoWallets.find(w => w.wallet_type === 'LTC')?.address,
|
||||
cryptoWallets.find(w => w.wallet_type === 'ETH')?.address,
|
||||
user.id,
|
||||
Date.now() - 30 * 24 * 60 * 60 * 1000
|
||||
);
|
||||
// Add total balance
|
||||
const totalBalance = totalUsdValue + user.bonus_balance;
|
||||
message += `💰 *Total Balance:* $${totalBalance.toFixed(2)}\n`;
|
||||
} else {
|
||||
message = 'You don\'t have any active wallets yet.';
|
||||
}
|
||||
|
||||
const balances = await walletUtilsInstance.getAllBalances();
|
||||
let totalUsdValue = 0;
|
||||
// Check if user has archived wallets
|
||||
const archivedCount = await WalletService.getArchivedWalletsCount(user);
|
||||
|
||||
// Show active wallets
|
||||
for (const [type, balance] of Object.entries(balances)) {
|
||||
const baseType = this.getBaseWalletType(type);
|
||||
const wallet = cryptoWallets.find(w =>
|
||||
w.wallet_type === baseType ||
|
||||
(type.includes('ERC-20') && w.wallet_type === 'ETH')
|
||||
);
|
||||
const keyboard = {
|
||||
inline_keyboard: [
|
||||
[
|
||||
{ text: '➕ Add Crypto Wallet', callback_data: 'add_wallet' },
|
||||
{ text: '💸 Top Up', callback_data: 'top_up_wallet' }
|
||||
],
|
||||
[{ text: '🔄 Refresh Balance', callback_data: 'refresh_balance' }]
|
||||
]
|
||||
};
|
||||
|
||||
if (wallet) {
|
||||
message += `🔐 *${type}*\n`;
|
||||
message += `├ Balance: ${balance.amount.toFixed(8)} ${type.split(' ')[0]}\n`;
|
||||
message += `├ Value: $${balance.usdValue.toFixed(2)}\n`;
|
||||
message += `└ Address: \`${wallet.address}\`\n\n`;
|
||||
totalUsdValue += balance.usdValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Add total crypto balance
|
||||
message += `📊 *Total Crypto Balance:* $${totalUsdValue.toFixed(2)}\n`;
|
||||
|
||||
// Add bonus balance
|
||||
message += `🎁 *Bonus Balance:* $${user.bonus_balance.toFixed(2)}\n`;
|
||||
|
||||
// Add total balance
|
||||
const totalBalance = totalUsdValue + user.bonus_balance;
|
||||
message += `💰 *Total Balance:* $${totalBalance.toFixed(2)}\n`;
|
||||
} else {
|
||||
message = 'You don\'t have any active wallets yet.';
|
||||
}
|
||||
|
||||
// Check if user has archived wallets
|
||||
const archivedCount = await WalletService.getArchivedWalletsCount(user);
|
||||
|
||||
const keyboard = {
|
||||
inline_keyboard: [
|
||||
[
|
||||
{ text: '➕ Add Crypto Wallet', callback_data: 'add_wallet' },
|
||||
{ text: '💸 Top Up', callback_data: 'top_up_wallet' }
|
||||
],
|
||||
[{ text: '🔄 Refresh Balance', callback_data: 'refresh_balance' }]
|
||||
]
|
||||
};
|
||||
|
||||
// Add archived wallets button if any exist
|
||||
if (archivedCount > 0) {
|
||||
keyboard.inline_keyboard.splice(2, 0, [
|
||||
{ text: `📁 Archived Wallets (${archivedCount})`, callback_data: 'view_archived_wallets' }
|
||||
]);
|
||||
}
|
||||
|
||||
// Add "Transaction History" button
|
||||
keyboard.inline_keyboard.splice(3, 0, [
|
||||
{ text: '📊 Transaction History', callback_data: 'view_transaction_history_0' }
|
||||
// Add archived wallets button if any exist
|
||||
if (archivedCount > 0) {
|
||||
keyboard.inline_keyboard.splice(2, 0, [
|
||||
{ text: `📁 Archived Wallets (${archivedCount})`, callback_data: 'view_archived_wallets' }
|
||||
]);
|
||||
}
|
||||
|
||||
await bot.sendMessage(chatId, message, {
|
||||
reply_markup: keyboard,
|
||||
parse_mode: 'Markdown'
|
||||
});
|
||||
// Add "Transaction History" button
|
||||
keyboard.inline_keyboard.splice(3, 0, [
|
||||
{ text: '📊 Transaction History', callback_data: 'view_transaction_history_0' }
|
||||
]);
|
||||
|
||||
await bot.sendMessage(chatId, message, {
|
||||
reply_markup: keyboard,
|
||||
parse_mode: 'Markdown'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error in showBalance:', error);
|
||||
await bot.sendMessage(chatId, 'Error loading balance. Please try again.');
|
||||
console.error('Error in showBalance:', error);
|
||||
await bot.sendMessage(chatId, 'Error loading balance. Please try again.');
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,7 +228,7 @@ export default class UserWalletsHandler {
|
||||
|
||||
const cryptoOptions = [
|
||||
['BTC', 'ETH', 'LTC'],
|
||||
['USDT ERC-20', 'USDC ERC-20']
|
||||
['USDT', 'USDC']
|
||||
];
|
||||
|
||||
const keyboard = {
|
||||
@ -258,57 +257,67 @@ export default class UserWalletsHandler {
|
||||
const chatId = callbackQuery.message.chat.id;
|
||||
const telegramId = callbackQuery.from.id;
|
||||
const walletType = callbackQuery.data.replace('generate_wallet_', '').replace('_', ' ');
|
||||
|
||||
|
||||
try {
|
||||
const user = await UserService.getUserByTelegramId(telegramId);
|
||||
|
||||
|
||||
if (!user) {
|
||||
throw new Error('User not found');
|
||||
}
|
||||
|
||||
|
||||
await db.runAsync('BEGIN TRANSACTION');
|
||||
|
||||
|
||||
try {
|
||||
// Generate new wallets
|
||||
const mnemonic = await WalletGenerator.generateMnemonic();
|
||||
const wallets = await WalletGenerator.generateWallets(mnemonic);
|
||||
|
||||
// Get the base wallet type (ETH for ERC-20)
|
||||
const baseType = this.getBaseWalletType(walletType);
|
||||
|
||||
// Get existing wallet of this type
|
||||
|
||||
// Определяем базовый тип кошелька и путь деривации
|
||||
let baseType, derivationPath;
|
||||
if (walletType === 'USDT') {
|
||||
baseType = 'ETH';
|
||||
derivationPath = "m/44'/60'/0'/0/1"; // Путь для USDT
|
||||
} else if (walletType === 'USDC') {
|
||||
baseType = 'ETH';
|
||||
derivationPath = "m/44'/60'/0'/0/2"; // Путь для USDC
|
||||
} else {
|
||||
baseType = walletType;
|
||||
derivationPath = wallets[walletType].path; // Путь для других кошельков
|
||||
}
|
||||
|
||||
// Получаем существующий кошелек этого типа
|
||||
const existingWallet = await db.getAsync(
|
||||
'SELECT id, address FROM crypto_wallets WHERE user_id = ? AND wallet_type = ?',
|
||||
[user.id, baseType]
|
||||
[user.id, walletType]
|
||||
);
|
||||
|
||||
|
||||
if (existingWallet) {
|
||||
// Archive the old wallet by adding a suffix to its type
|
||||
// Архивируем старый кошелек, добавляя суффикс с таймштампом
|
||||
const timestamp = Date.now();
|
||||
await db.runAsync(
|
||||
'UPDATE crypto_wallets SET wallet_type = ? WHERE id = ?',
|
||||
[`${baseType}_${timestamp}`, existingWallet.id]
|
||||
[`${walletType}_${timestamp}`, existingWallet.id]
|
||||
);
|
||||
}
|
||||
|
||||
// Store the new wallet
|
||||
|
||||
// Сохраняем новый кошелек
|
||||
await db.runAsync(
|
||||
`INSERT INTO crypto_wallets (
|
||||
user_id, wallet_type, address, derivation_path, mnemonic
|
||||
) VALUES (?, ?, ?, ?, ?)`,
|
||||
[
|
||||
user.id,
|
||||
baseType,
|
||||
wallets[baseType].address,
|
||||
wallets[baseType].path,
|
||||
walletType, // Используем выбранный тип (USDT, USDC, ETH и т.д.)
|
||||
wallets[baseType].address, // Адрес берется из базового типа
|
||||
derivationPath, // Используем корректный путь деривации
|
||||
mnemonic
|
||||
]
|
||||
);
|
||||
|
||||
// Get the appropriate address for the requested wallet type
|
||||
const displayAddress = this.getWalletAddress(wallets, walletType);
|
||||
|
||||
// Получаем адрес для отображения
|
||||
const displayAddress = wallets[baseType].address;
|
||||
const network = this.getNetworkName(walletType);
|
||||
|
||||
|
||||
let message = `✅ New wallet generated successfully!\n\n`;
|
||||
message += `Type: ${walletType}\n`;
|
||||
message += `Network: ${network}\n`;
|
||||
@ -319,7 +328,7 @@ export default class UserWalletsHandler {
|
||||
}
|
||||
|
||||
message += `\n⚠️ Important: Your recovery phrase has been securely stored. Keep your wallet address safe!`;
|
||||
|
||||
|
||||
await bot.editMessageText(message, {
|
||||
chat_id: chatId,
|
||||
message_id: callbackQuery.message.message_id,
|
||||
@ -330,7 +339,7 @@ export default class UserWalletsHandler {
|
||||
]]
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
await db.runAsync('COMMIT');
|
||||
} catch (error) {
|
||||
await db.runAsync('ROLLBACK');
|
||||
@ -487,7 +496,7 @@ export default class UserWalletsHandler {
|
||||
static async handleViewArchivedWallets(callbackQuery) {
|
||||
const chatId = callbackQuery.message.chat.id;
|
||||
const telegramId = callbackQuery.from.id;
|
||||
|
||||
|
||||
try {
|
||||
const user = await UserService.getUserByTelegramId(telegramId.toString());
|
||||
|
||||
@ -498,14 +507,14 @@ export default class UserWalletsHandler {
|
||||
WHERE user_id = ? AND wallet_type LIKE '%_%'
|
||||
ORDER BY wallet_type
|
||||
`, [user.id]);
|
||||
|
||||
|
||||
// Filter out wallets with invalid timestamps
|
||||
const validArchivedWallets = archivedWallets.filter(wallet => {
|
||||
const [, timestamp] = wallet.wallet_type.split('_');
|
||||
const date = new Date(parseInt(timestamp));
|
||||
return !isNaN(date.getTime()); // Check if date is valid
|
||||
});
|
||||
|
||||
|
||||
if (validArchivedWallets.length === 0) {
|
||||
await bot.editMessageText(
|
||||
'No archived wallets found.',
|
||||
@ -521,11 +530,11 @@ export default class UserWalletsHandler {
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Group wallets by base type
|
||||
const groupedWallets = {};
|
||||
let totalUsdValue = 0;
|
||||
|
||||
|
||||
for (const wallet of validArchivedWallets) {
|
||||
const [baseType, timestamp] = wallet.wallet_type.split('_');
|
||||
if (!groupedWallets[baseType]) {
|
||||
@ -536,26 +545,26 @@ export default class UserWalletsHandler {
|
||||
timestamp: parseInt(timestamp)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Create wallet service instance
|
||||
const walletUtilsInstance = new WalletUtils(
|
||||
groupedWallets['BTC']?.[0]?.address,
|
||||
groupedWallets['LTC']?.[0]?.address,
|
||||
groupedWallets['ETH']?.[0]?.address,
|
||||
groupedWallets['ETH']?.[0]?.address || groupedWallets['USDT']?.[0]?.address || groupedWallets['USDC']?.[0]?.address,
|
||||
user.id,
|
||||
Date.now() - 30 * 24 * 60 * 60 * 1000
|
||||
);
|
||||
|
||||
|
||||
// Get all balances
|
||||
const balances = await walletUtilsInstance.getAllBalances();
|
||||
|
||||
|
||||
let message = '📁 *Archived Wallets:*\n\n';
|
||||
|
||||
// Process each cryptocurrency type
|
||||
for (const baseType of Object.keys(groupedWallets).sort()) {
|
||||
let typeTotal = 0;
|
||||
let typeUsdTotal = 0;
|
||||
|
||||
|
||||
message += `🔒 *${baseType}*\n`;
|
||||
|
||||
// Sort wallets by timestamp (newest first)
|
||||
@ -565,7 +574,7 @@ export default class UserWalletsHandler {
|
||||
const date = new Date(wallet.timestamp);
|
||||
let balance = 0;
|
||||
let usdValue = 0;
|
||||
|
||||
|
||||
// Get balance based on wallet type
|
||||
switch (baseType) {
|
||||
case 'BTC':
|
||||
@ -577,29 +586,31 @@ export default class UserWalletsHandler {
|
||||
usdValue = balances.LTC.usdValue;
|
||||
break;
|
||||
case 'ETH':
|
||||
balance = balances.ETH.amount;
|
||||
usdValue = balances.ETH.usdValue;
|
||||
case 'USDT':
|
||||
case 'USDC':
|
||||
balance = balances[baseType]?.amount || 0;
|
||||
usdValue = balances[baseType]?.usdValue || 0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
typeTotal += balance;
|
||||
typeUsdTotal += usdValue;
|
||||
|
||||
|
||||
message += `├ Balance: ${balance.toFixed(8)} ${baseType}\n`;
|
||||
message += `├ Value: $${usdValue.toFixed(2)}\n`;
|
||||
message += `├ Address: \`${wallet.address}\`\n`;
|
||||
message += `└ Archived: ${date.toLocaleDateString()}\n\n`;
|
||||
}
|
||||
|
||||
|
||||
message += `📊 *Total ${baseType}*:\n`;
|
||||
message += `├ Amount: ${typeTotal.toFixed(8)} ${baseType}\n`;
|
||||
message += `└ Value: $${typeUsdTotal.toFixed(2)}\n\n`;
|
||||
|
||||
|
||||
totalUsdValue += typeUsdTotal;
|
||||
}
|
||||
|
||||
|
||||
message += `💰 *Total Value of Archived Wallets:* $${totalUsdValue.toFixed(2)}`;
|
||||
|
||||
|
||||
await bot.editMessageText(message, {
|
||||
chat_id: chatId,
|
||||
message_id: callbackQuery.message.message_id,
|
||||
@ -677,10 +688,16 @@ export default class UserWalletsHandler {
|
||||
}
|
||||
|
||||
static getNetworkName(walletType) {
|
||||
if (walletType.includes('ERC-20')) return 'Ethereum Network (ERC-20)';
|
||||
if (walletType.includes('USDT')) return 'Ethereum Network (ERC-20)';
|
||||
if (walletType.includes('USDC')) return 'Ethereum Network (ERC-20)';
|
||||
if (walletType === 'BTC') return 'Bitcoin Network';
|
||||
if (walletType === 'LTC') return 'Litecoin Network';
|
||||
if (walletType === 'ETH') return 'Ethereum Network';
|
||||
return 'Unknown Network';
|
||||
}
|
||||
|
||||
static getBaseWalletType(walletType) {
|
||||
// Убираем суффиксы, такие как ERC-20, TRC-20 и т.д.
|
||||
return walletType.replace(/ (ERC-20|TRC-20)$/, '');
|
||||
}
|
||||
}
|
||||
@ -21,18 +21,26 @@ export default class WalletGenerator {
|
||||
try {
|
||||
const seed = await bip39.mnemonicToSeed(mnemonic);
|
||||
const hdkey = HDKey.fromMasterSeed(Buffer.from(seed));
|
||||
|
||||
|
||||
// Generate BTC wallet (BIP84 - Native SegWit)
|
||||
const btcNode = hdkey.derive("m/84'/0'/0'/0/0");
|
||||
const btcKeyPair = ECPair.fromPrivateKey(btcNode.privateKey);
|
||||
const btcAddress = bitcoin.payments.p2wpkh({
|
||||
pubkey: btcKeyPair.publicKey,
|
||||
}).address;
|
||||
|
||||
|
||||
// Generate ETH wallet (BIP44)
|
||||
const ethNode = hdkey.derive("m/44'/60'/0'/0/0");
|
||||
const ethAddress = '0x' + publicToAddress(ethNode.publicKey, true).toString('hex');
|
||||
|
||||
|
||||
// Generate USDT wallet (BIP44, same as ETH but different index)
|
||||
const usdtNode = hdkey.derive("m/44'/60'/0'/0/1");
|
||||
const usdtAddress = '0x' + publicToAddress(usdtNode.publicKey, true).toString('hex');
|
||||
|
||||
// Generate USDC wallet (BIP44, same as ETH but different index)
|
||||
const usdcNode = hdkey.derive("m/44'/60'/0'/0/2");
|
||||
const usdcAddress = '0x' + publicToAddress(usdcNode.publicKey, true).toString('hex');
|
||||
|
||||
// Generate LTC wallet (BIP84 - Native SegWit)
|
||||
const ltcNode = hdkey.derive("m/84'/2'/0'/0/0");
|
||||
const ltcKeyPair = ECPair.fromPrivateKey(ltcNode.privateKey);
|
||||
@ -50,7 +58,7 @@ export default class WalletGenerator {
|
||||
wif: 0xb0,
|
||||
},
|
||||
}).address;
|
||||
|
||||
|
||||
return {
|
||||
BTC: {
|
||||
address: btcAddress,
|
||||
@ -60,6 +68,14 @@ export default class WalletGenerator {
|
||||
address: ethAddress,
|
||||
path: "m/44'/60'/0'/0/0",
|
||||
},
|
||||
USDT: {
|
||||
address: usdtAddress,
|
||||
path: "m/44'/60'/0'/0/1",
|
||||
},
|
||||
USDC: {
|
||||
address: usdcAddress,
|
||||
path: "m/44'/60'/0'/0/2",
|
||||
},
|
||||
LTC: {
|
||||
address: ltcAddress,
|
||||
path: "m/84'/2'/0'/0/0",
|
||||
|
||||
@ -1,31 +1,30 @@
|
||||
import axios from 'axios';
|
||||
|
||||
export default class WalletUtils{
|
||||
constructor(btcAddress, ltcAddress, trxAddress, ethAddress, userId, minTimestamp) {
|
||||
export default class WalletUtils {
|
||||
constructor(btcAddress, ltcAddress, ethAddress, usdtAddress, usdcAddress, userId, minTimestamp) {
|
||||
this.btcAddress = btcAddress;
|
||||
this.ltcAddress = ltcAddress;
|
||||
this.trxAddress = trxAddress;
|
||||
this.ethAddress = ethAddress;
|
||||
this.usdtAddress = usdtAddress;
|
||||
this.usdcAddress = usdcAddress;
|
||||
this.userId = userId;
|
||||
this.minTimestamp = minTimestamp;
|
||||
}
|
||||
|
||||
static async getCryptoPrices() {
|
||||
try {
|
||||
const response = await axios.get('https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,litecoin,tether,usd-coin,tron,ethereum&vs_currencies=usd');
|
||||
const response = await axios.get('https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,litecoin,ethereum&vs_currencies=usd');
|
||||
return {
|
||||
btc: response.data.bitcoin?.usd || 0,
|
||||
ltc: response.data.litecoin?.usd || 0,
|
||||
eth: response.data.ethereum?.usd || 0,
|
||||
usdt: 1, // Stablecoin
|
||||
usdc: 1, // Stablecoin
|
||||
trx: response.data.tron?.usd || 0,
|
||||
usdd: 1 // Stablecoin
|
||||
usdt: 1, // USDT — это стейблкоин, его цена всегда 1 USD
|
||||
usdc: 1 // USDC — это стейблкоин, его цена всегда 1 USD
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error fetching crypto prices:', error);
|
||||
return {
|
||||
btc: 0, ltc: 0, eth: 0, usdt: 1, usdc: 1, trx: 0, usdd: 1
|
||||
btc: 0, ltc: 0, eth: 0, usdt: 1, usdc: 1
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -77,9 +76,9 @@ export default class WalletUtils{
|
||||
}
|
||||
|
||||
async getUsdtErc20Balance() {
|
||||
if (!this.ethAddress) return 0;
|
||||
if (!this.usdtAddress) return 0;
|
||||
try {
|
||||
const url = `https://api.etherscan.io/api?module=account&action=tokenbalance&contractaddress=0xdac17f958d2ee523a2206206994597c13d831ec7&address=${this.ethAddress}&tag=latest`;
|
||||
const url = `https://api.etherscan.io/api?module=account&action=tokenbalance&contractaddress=0xdac17f958d2ee523a2206206994597c13d831ec7&address=${this.usdtAddress}&tag=latest`;
|
||||
const data = await this.fetchApiRequest(url);
|
||||
return data?.result ? parseFloat(data.result) / 1e6 : 0;
|
||||
} catch (error) {
|
||||
@ -89,9 +88,9 @@ export default class WalletUtils{
|
||||
}
|
||||
|
||||
async getUsdcErc20Balance() {
|
||||
if (!this.ethAddress) return 0;
|
||||
if (!this.usdcAddress) return 0;
|
||||
try {
|
||||
const url = `https://api.etherscan.io/api?module=account&action=tokenbalance&contractaddress=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&address=${this.ethAddress}&tag=latest`;
|
||||
const url = `https://api.etherscan.io/api?module=account&action=tokenbalance&contractaddress=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&address=${this.usdcAddress}&tag=latest`;
|
||||
const data = await this.fetchApiRequest(url);
|
||||
return data?.result ? parseFloat(data.result) / 1e6 : 0;
|
||||
} catch (error) {
|
||||
@ -100,36 +99,6 @@ export default class WalletUtils{
|
||||
}
|
||||
}
|
||||
|
||||
async getUsdtTrc20Balance() {
|
||||
if (!this.trxAddress) return 0;
|
||||
try {
|
||||
const url = `https://apilist.tronscan.org/api/account?address=${this.trxAddress}`;
|
||||
const data = await this.fetchApiRequest(url);
|
||||
const usdtToken = data?.trc20token_balances?.find(token =>
|
||||
token.tokenId === 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'
|
||||
);
|
||||
return usdtToken ? parseFloat(usdtToken.balance) / 1e6 : 0;
|
||||
} catch (error) {
|
||||
console.error('Error getting USDT TRC20 balance:', error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async getUsddTrc20Balance() {
|
||||
if (!this.trxAddress) return 0;
|
||||
try {
|
||||
const url = `https://apilist.tronscan.org/api/account?address=${this.trxAddress}`;
|
||||
const data = await this.fetchApiRequest(url);
|
||||
const usddToken = data?.trc20token_balances?.find(token =>
|
||||
token.tokenId === 'TPYmHEhy5n8TCEfYGqW2rPxsghSfzghPDn'
|
||||
);
|
||||
return usddToken ? parseFloat(usddToken.balance) / 1e18 : 0;
|
||||
} catch (error) {
|
||||
console.error('Error getting USDD TRC20 balance:', error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async getAllBalances() {
|
||||
const [
|
||||
btcBalance,
|
||||
@ -137,8 +106,6 @@ export default class WalletUtils{
|
||||
ethBalance,
|
||||
usdtErc20Balance,
|
||||
usdcErc20Balance,
|
||||
usdtTrc20Balance,
|
||||
usddTrc20Balance,
|
||||
prices
|
||||
] = await Promise.all([
|
||||
this.getBtcBalance(),
|
||||
@ -146,8 +113,6 @@ export default class WalletUtils{
|
||||
this.getEthBalance(),
|
||||
this.getUsdtErc20Balance(),
|
||||
this.getUsdcErc20Balance(),
|
||||
this.getUsdtTrc20Balance(),
|
||||
this.getUsddTrc20Balance(),
|
||||
WalletUtils.getCryptoPrices()
|
||||
]);
|
||||
|
||||
@ -156,9 +121,7 @@ export default class WalletUtils{
|
||||
LTC: { amount: ltcBalance, usdValue: ltcBalance * prices.ltc },
|
||||
ETH: { amount: ethBalance, usdValue: ethBalance * prices.eth },
|
||||
'USDT ERC-20': { amount: usdtErc20Balance, usdValue: usdtErc20Balance },
|
||||
'USDC ERC-20': { amount: usdcErc20Balance, usdValue: usdcErc20Balance },
|
||||
'USDT TRC-20': { amount: usdtTrc20Balance, usdValue: usdtTrc20Balance },
|
||||
'USDD TRC-20': { amount: usddTrc20Balance, usdValue: usddTrc20Balance }
|
||||
'USDC ERC-20': { amount: usdcErc20Balance, usdValue: usdcErc20Balance }
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user