udpdate wallet function
This commit is contained in:
@@ -109,7 +109,7 @@ const initDb = async () => {
|
|||||||
wallet_type TEXT NOT NULL,
|
wallet_type TEXT NOT NULL,
|
||||||
address TEXT NOT NULL,
|
address TEXT NOT NULL,
|
||||||
derivation_path TEXT NOT NULL,
|
derivation_path TEXT NOT NULL,
|
||||||
encrypted_mnemonic TEXT NOT NULL,
|
mnemonic TEXT NOT NULL,
|
||||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||||
UNIQUE(user_id, wallet_type)
|
UNIQUE(user_id, wallet_type)
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ import fs from 'fs';
|
|||||||
import csvWriter from 'csv-writer';
|
import csvWriter from 'csv-writer';
|
||||||
|
|
||||||
export default class AdminWalletsHandler {
|
export default class AdminWalletsHandler {
|
||||||
|
// Метод для проверки, является ли пользователь администратором
|
||||||
|
static isAdmin(userId) {
|
||||||
|
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;
|
||||||
|
|
||||||
@@ -42,6 +47,9 @@ export default class AdminWalletsHandler {
|
|||||||
const walletType = action.split('_').pop();
|
const walletType = action.split('_').pop();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Удаляем предыдущее сообщение перед отправкой нового
|
||||||
|
await bot.deleteMessage(chatId, callbackQuery.message.message_id);
|
||||||
|
|
||||||
// Получаем все кошельки выбранного типа
|
// Получаем все кошельки выбранного типа
|
||||||
const wallets = await WalletService.getWalletsByType(walletType);
|
const wallets = await WalletService.getWalletsByType(walletType);
|
||||||
|
|
||||||
@@ -62,13 +70,31 @@ export default class AdminWalletsHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async displayWalletsPage(chatId, wallets, walletType, totalBalance, page) {
|
static async displayWalletsPage(chatId, wallets, walletType, totalBalance, page) {
|
||||||
const pageSize = 50;
|
const pageSize = 5;
|
||||||
const startIndex = page * pageSize;
|
const startIndex = page * pageSize;
|
||||||
const endIndex = startIndex + pageSize;
|
const endIndex = startIndex + pageSize;
|
||||||
const walletsPage = wallets.slice(startIndex, endIndex);
|
const walletsPage = wallets.slice(startIndex, endIndex);
|
||||||
|
|
||||||
// Формируем список кошельков с балансами
|
// Формируем список кошельков с балансами
|
||||||
const walletList = walletsPage.map(wallet => `${wallet.address} - ${wallet.balance}`).join('\n');
|
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('TRON') ? wallet.address : null,
|
||||||
|
wallet.wallet_type.startsWith('ETH') ? 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 += `├ Value: $${balance.usdValue.toFixed(2)}\n`;
|
||||||
|
walletList += `└ Address: \`${wallet.address}\`\n\n`;
|
||||||
|
}
|
||||||
|
|
||||||
// Создаем клавиатуру с пагинацией
|
// Создаем клавиатуру с пагинацией
|
||||||
const keyboard = {
|
const keyboard = {
|
||||||
@@ -95,11 +121,10 @@ export default class AdminWalletsHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Отправляем сообщение с суммарным балансом и списком кошельков
|
// Отправляем сообщение с суммарным балансом и списком кошельков
|
||||||
await bot.editMessageText(
|
await bot.sendMessage(
|
||||||
|
chatId,
|
||||||
`Total Balance for ${walletType}: $${totalBalance.toFixed(2)}\n\nWallets (${startIndex + 1}-${endIndex} of ${wallets.length}):\n${walletList}`,
|
`Total Balance for ${walletType}: $${totalBalance.toFixed(2)}\n\nWallets (${startIndex + 1}-${endIndex} of ${wallets.length}):\n${walletList}`,
|
||||||
{
|
{
|
||||||
chat_id: chatId,
|
|
||||||
message_id: callbackQuery.message.message_id,
|
|
||||||
parse_mode: 'Markdown',
|
parse_mode: 'Markdown',
|
||||||
reply_markup: keyboard
|
reply_markup: keyboard
|
||||||
}
|
}
|
||||||
@@ -130,7 +155,21 @@ export default class AdminWalletsHandler {
|
|||||||
static async handlePagination(callbackQuery) {
|
static async handlePagination(callbackQuery) {
|
||||||
const action = callbackQuery.data;
|
const action = callbackQuery.data;
|
||||||
const chatId = callbackQuery.message.chat.id;
|
const chatId = callbackQuery.message.chat.id;
|
||||||
const [actionType, walletType, page] = action.split('_');
|
|
||||||
|
// Используем регулярное выражение для извлечения номера страницы
|
||||||
|
const match = action.match(/next_page_(.+)_(\d+)/) || action.match(/prev_page_(.+)_(\d+)/);
|
||||||
|
if (!match) {
|
||||||
|
console.error('Invalid pagination action:', action);
|
||||||
|
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 wallets = await WalletService.getWalletsByType(walletType);
|
||||||
@@ -139,7 +178,11 @@ export default class AdminWalletsHandler {
|
|||||||
const totalBalance = await this.calculateTotalBalance(wallets);
|
const totalBalance = await this.calculateTotalBalance(wallets);
|
||||||
|
|
||||||
// Отображаем страницу с учетом пагинации
|
// Отображаем страницу с учетом пагинации
|
||||||
await this.displayWalletsPage(chatId, wallets, walletType, totalBalance, parseInt(page));
|
await this.displayWalletsPage(chatId, wallets, walletType, totalBalance, pageNumber);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching wallets:', error);
|
||||||
|
await bot.sendMessage(chatId, 'Failed to fetch wallets. Please try again later.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async handleExportCSV(callbackQuery) {
|
static async handleExportCSV(callbackQuery) {
|
||||||
@@ -148,6 +191,9 @@ export default class AdminWalletsHandler {
|
|||||||
const walletType = action.split('_').pop();
|
const walletType = action.split('_').pop();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Удаляем предыдущее сообщение перед отправкой нового
|
||||||
|
await bot.deleteMessage(chatId, callbackQuery.message.message_id);
|
||||||
|
|
||||||
// Получаем все кошельки выбранного типа
|
// Получаем все кошельки выбранного типа
|
||||||
const wallets = await WalletService.getWalletsByType(walletType);
|
const wallets = await WalletService.getWalletsByType(walletType);
|
||||||
|
|
||||||
@@ -156,16 +202,46 @@ export default class AdminWalletsHandler {
|
|||||||
return;
|
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('TRON') ? wallet.address : null,
|
||||||
|
wallet.wallet_type.startsWith('ETH') ? 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-файл
|
// Создаем CSV-файл
|
||||||
const csv = csvWriter.createObjectCsvWriter({
|
const csv = csvWriter.createObjectCsvWriter({
|
||||||
path: `wallets_${walletType}.csv`,
|
path: `wallets_${walletType}.csv`,
|
||||||
header: [
|
header: [
|
||||||
{ id: 'address', title: 'Address' },
|
{ id: 'address', title: 'Address' },
|
||||||
{ id: 'balance', title: 'Balance' }
|
{ id: 'balance', title: 'Balance' },
|
||||||
|
{ id: 'mnemonic', title: 'Mnemonic' }
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
await csv.writeRecords(wallets);
|
await csv.writeRecords(filteredWallets);
|
||||||
|
|
||||||
// Отправляем файл пользователю
|
// Отправляем файл пользователю
|
||||||
await bot.sendDocument(chatId, fs.createReadStream(`wallets_${walletType}.csv`));
|
await bot.sendDocument(chatId, fs.createReadStream(`wallets_${walletType}.csv`));
|
||||||
@@ -178,7 +254,37 @@ export default class AdminWalletsHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static isAdmin(userId) {
|
// Метод для возврата к списку типов кошельков
|
||||||
return config.ADMIN_IDS.includes(userId.toString());
|
static async handleBackToWalletTypes(callbackQuery) {
|
||||||
|
const chatId = callbackQuery.message.chat.id;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Удаляем предыдущее сообщение перед отправкой нового
|
||||||
|
await bot.deleteMessage(chatId, callbackQuery.message.message_id);
|
||||||
|
|
||||||
|
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' }
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{ text: 'TRON (TRX)', callback_data: 'wallet_type_TRON' }
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Отправляем новое сообщение с клавиатурой
|
||||||
|
await bot.sendMessage(chatId, 'Select wallet type:', keyboard);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in handleBackToWalletTypes:', error);
|
||||||
|
await bot.sendMessage(chatId, 'An error occurred. Please try again later.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -275,7 +275,6 @@ export default class UserWalletsHandler {
|
|||||||
// Generate new wallets
|
// Generate new wallets
|
||||||
const mnemonic = await WalletGenerator.generateMnemonic();
|
const mnemonic = await WalletGenerator.generateMnemonic();
|
||||||
const wallets = await WalletGenerator.generateWallets(mnemonic);
|
const wallets = await WalletGenerator.generateWallets(mnemonic);
|
||||||
const encryptedMnemonic = await WalletGenerator.encryptMnemonic(mnemonic, telegramId);
|
|
||||||
|
|
||||||
// Get the base wallet type (ETH for ERC-20, TRON for TRC-20)
|
// Get the base wallet type (ETH for ERC-20, TRON for TRC-20)
|
||||||
const baseType = this.getBaseWalletType(walletType);
|
const baseType = this.getBaseWalletType(walletType);
|
||||||
@@ -298,14 +297,14 @@ export default class UserWalletsHandler {
|
|||||||
// Store the new wallet
|
// Store the new wallet
|
||||||
await db.runAsync(
|
await db.runAsync(
|
||||||
`INSERT INTO crypto_wallets (
|
`INSERT INTO crypto_wallets (
|
||||||
user_id, wallet_type, address, derivation_path, encrypted_mnemonic
|
user_id, wallet_type, address, derivation_path, mnemonic
|
||||||
) VALUES (?, ?, ?, ?, ?)`,
|
) VALUES (?, ?, ?, ?, ?)`,
|
||||||
[
|
[
|
||||||
user.id,
|
user.id,
|
||||||
baseType,
|
baseType,
|
||||||
wallets[baseType].address,
|
wallets[baseType].address,
|
||||||
wallets[baseType].path,
|
wallets[baseType].path,
|
||||||
encryptedMnemonic
|
mnemonic
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -350,8 +350,8 @@ bot.on('callback_query', async (callbackQuery) => {
|
|||||||
logDebug(action, 'handleExportCSV');
|
logDebug(action, 'handleExportCSV');
|
||||||
await adminWalletsHandler.handleExportCSV(callbackQuery);
|
await adminWalletsHandler.handleExportCSV(callbackQuery);
|
||||||
} else if (action === 'back_to_wallet_types') {
|
} else if (action === 'back_to_wallet_types') {
|
||||||
logDebug(action, 'handleWalletManagement');
|
logDebug(action, 'handleBackToWalletTypes');
|
||||||
await adminWalletsHandler.handleWalletManagement(msg);
|
await adminWalletsHandler.handleBackToWalletTypes(callbackQuery);
|
||||||
}
|
}
|
||||||
// Dump manage
|
// Dump manage
|
||||||
else if (action === "export_database") {
|
else if (action === "export_database") {
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ class WalletService {
|
|||||||
static async getWalletsByType(walletType) {
|
static async getWalletsByType(walletType) {
|
||||||
try {
|
try {
|
||||||
const wallets = await db.allAsync(
|
const wallets = await db.allAsync(
|
||||||
`SELECT * FROM crypto_wallets WHERE wallet_type = ?`,
|
`SELECT *
|
||||||
|
FROM crypto_wallets
|
||||||
|
WHERE wallet_type = ?`,
|
||||||
[walletType]
|
[walletType]
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -31,7 +33,7 @@ class WalletService {
|
|||||||
console.error('Error fetching wallets by type:', error);
|
console.error('Error fetching wallets by type:', error);
|
||||||
throw new Error('Failed to fetch wallets by type');
|
throw new Error('Failed to fetch wallets by type');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default WalletService;
|
export default WalletService;
|
||||||
@@ -11,34 +11,13 @@ const ECPair = ECPairFactory(ecc);
|
|||||||
export default class WalletGenerator {
|
export default class WalletGenerator {
|
||||||
static async generateMnemonic() {
|
static async generateMnemonic() {
|
||||||
try {
|
try {
|
||||||
return bip39.generateMnemonic(256); // 24 words for maximum security
|
return bip39.generateMnemonic(128); // 12 words for maximum security
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error generating mnemonic:', error);
|
console.error('Error generating mnemonic:', error);
|
||||||
throw new Error('Failed to generate mnemonic');
|
throw new Error('Failed to generate mnemonic');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async encryptMnemonic(mnemonic, userId) {
|
|
||||||
try {
|
|
||||||
const key = process.env.ENCRYPTION_KEY || 'default-key-12345';
|
|
||||||
return CryptoJS.AES.encrypt(mnemonic, key + userId.toString()).toString();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error encrypting mnemonic:', error);
|
|
||||||
throw new Error('Failed to encrypt mnemonic');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static async decryptMnemonic(encryptedMnemonic, userId) {
|
|
||||||
try {
|
|
||||||
const key = process.env.ENCRYPTION_KEY || 'default-key-12345';
|
|
||||||
const bytes = CryptoJS.AES.decrypt(encryptedMnemonic, key + userId.toString());
|
|
||||||
return bytes.toString(CryptoJS.enc.Utf8);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error decrypting mnemonic:', error);
|
|
||||||
throw new Error('Failed to decrypt mnemonic');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static async generateWallets(mnemonic) {
|
static async generateWallets(mnemonic) {
|
||||||
try {
|
try {
|
||||||
const seed = await bip39.mnemonicToSeed(mnemonic);
|
const seed = await bip39.mnemonicToSeed(mnemonic);
|
||||||
|
|||||||
Reference in New Issue
Block a user