Initial commit
This commit is contained in:
24
src/utils/errorHandler.js
Normal file
24
src/utils/errorHandler.js
Normal file
@@ -0,0 +1,24 @@
|
||||
export default class ErrorHandler {
|
||||
static async handleError(bot, chatId, error, context) {
|
||||
console.error(`Error in ${context}:`, error);
|
||||
|
||||
const errorMessage = process.env.NODE_ENV === 'development'
|
||||
? `Error: ${error.message}`
|
||||
: 'An error occurred. Please try again later.';
|
||||
|
||||
try {
|
||||
await bot.sendMessage(chatId, errorMessage);
|
||||
} catch (sendError) {
|
||||
console.error('Error sending error message:', sendError);
|
||||
}
|
||||
}
|
||||
|
||||
static handlePollingError(error) {
|
||||
if (error.code === 'ETELEGRAM') {
|
||||
console.error('Telegram API Error:', error.message);
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.error('Polling error:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
src/utils/validators.js
Normal file
22
src/utils/validators.js
Normal file
@@ -0,0 +1,22 @@
|
||||
export default class Validators {
|
||||
static isValidLocation(country, city, district) {
|
||||
return Boolean(country && city && district);
|
||||
}
|
||||
|
||||
static isValidProduct(product) {
|
||||
return Boolean(
|
||||
product.name &&
|
||||
product.category &&
|
||||
product.price &&
|
||||
product.price > 0
|
||||
);
|
||||
}
|
||||
|
||||
static isValidQuantity(quantity, stock) {
|
||||
return quantity > 0 && quantity <= stock;
|
||||
}
|
||||
|
||||
static isValidBalance(balance) {
|
||||
return balance >= 0;
|
||||
}
|
||||
}
|
||||
148
src/utils/walletGenerator.js
Normal file
148
src/utils/walletGenerator.js
Normal file
@@ -0,0 +1,148 @@
|
||||
import bip39 from 'bip39';
|
||||
import HDKey from 'hdkey';
|
||||
import { publicToAddress } from 'ethereumjs-util';
|
||||
import * as bitcoin from 'bitcoinjs-lib';
|
||||
import * as ecc from 'tiny-secp256k1';
|
||||
import { ECPairFactory } from 'ecpair';
|
||||
import CryptoJS from 'crypto-js';
|
||||
|
||||
const ECPair = ECPairFactory(ecc);
|
||||
|
||||
export default class WalletGenerator {
|
||||
static async generateMnemonic() {
|
||||
try {
|
||||
return bip39.generateMnemonic(256); // 24 words for maximum security
|
||||
} catch (error) {
|
||||
console.error('Error generating mnemonic:', error);
|
||||
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) {
|
||||
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 LTC wallet (BIP84 - Native SegWit)
|
||||
const ltcNode = hdkey.derive("m/84'/2'/0'/0/0");
|
||||
const ltcKeyPair = ECPair.fromPrivateKey(ltcNode.privateKey);
|
||||
const ltcAddress = bitcoin.payments.p2wpkh({
|
||||
pubkey: ltcKeyPair.publicKey,
|
||||
network: {
|
||||
messagePrefix: '\x19Litecoin Signed Message:\n',
|
||||
bech32: 'ltc',
|
||||
bip32: {
|
||||
public: 0x019da462,
|
||||
private: 0x019d9cfe
|
||||
},
|
||||
pubKeyHash: 0x30,
|
||||
scriptHash: 0x32,
|
||||
wif: 0xb0
|
||||
}
|
||||
}).address;
|
||||
|
||||
// Generate TRON address (BIP44)
|
||||
const tronNode = hdkey.derive("m/44'/195'/0'/0/0");
|
||||
const tronAddress = this.generateTronAddress(tronNode.publicKey);
|
||||
|
||||
return {
|
||||
BTC: {
|
||||
address: btcAddress,
|
||||
path: "m/84'/0'/0'/0/0"
|
||||
},
|
||||
ETH: {
|
||||
address: ethAddress,
|
||||
path: "m/44'/60'/0'/0/0"
|
||||
},
|
||||
LTC: {
|
||||
address: ltcAddress,
|
||||
path: "m/84'/2'/0'/0/0"
|
||||
},
|
||||
TRON: {
|
||||
address: tronAddress,
|
||||
path: "m/44'/195'/0'/0/0"
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error in generateWallets:', error);
|
||||
throw new Error('Failed to generate cryptocurrency wallets: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
static generateTronAddress(publicKey) {
|
||||
try {
|
||||
const addressPrefix = '41'; // TRON mainnet prefix
|
||||
const pubKeyHash = CryptoJS.SHA256(
|
||||
CryptoJS.lib.WordArray.create(publicKey)
|
||||
).toString();
|
||||
|
||||
const address = addressPrefix + pubKeyHash.substring(0, 40);
|
||||
return this.base58Encode(Buffer.from(address, 'hex'));
|
||||
} catch (error) {
|
||||
console.error('Error generating TRON address:', error);
|
||||
throw new Error('Failed to generate TRON address: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
static base58Encode(buffer) {
|
||||
try {
|
||||
const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
||||
let digits = [0];
|
||||
|
||||
for (let i = 0; i < buffer.length; i++) {
|
||||
let carry = buffer[i];
|
||||
for (let j = 0; j < digits.length; j++) {
|
||||
carry += digits[j] << 8;
|
||||
digits[j] = carry % 58;
|
||||
carry = (carry / 58) | 0;
|
||||
}
|
||||
while (carry > 0) {
|
||||
digits.push(carry % 58);
|
||||
carry = (carry / 58) | 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Add leading zeros
|
||||
for (let i = 0; buffer[i] === 0 && i < buffer.length - 1; i++) {
|
||||
digits.push(0);
|
||||
}
|
||||
|
||||
return digits.reverse().map(digit => ALPHABET[digit]).join('');
|
||||
} catch (error) {
|
||||
console.error('Error in base58Encode:', error);
|
||||
throw new Error('Failed to encode address: ' + error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
164
src/utils/walletService.js
Normal file
164
src/utils/walletService.js
Normal file
@@ -0,0 +1,164 @@
|
||||
import axios from 'axios';
|
||||
|
||||
export default class WalletService {
|
||||
constructor(btcAddress, ltcAddress, trxAddress, ethAddress, userId, minTimestamp) {
|
||||
this.btcAddress = btcAddress;
|
||||
this.ltcAddress = ltcAddress;
|
||||
this.trxAddress = trxAddress;
|
||||
this.ethAddress = ethAddress;
|
||||
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');
|
||||
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
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error fetching crypto prices:', error);
|
||||
return {
|
||||
btc: 0, ltc: 0, eth: 0, usdt: 1, usdc: 1, trx: 0, usdd: 1
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async fetchApiRequest(url) {
|
||||
try {
|
||||
const response = await axios.get(url);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error(`Error fetching data from ${url}:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async getBtcBalance() {
|
||||
if (!this.btcAddress) return 0;
|
||||
try {
|
||||
const url = `https://blockchain.info/balance?active=${this.btcAddress}`;
|
||||
const data = await this.fetchApiRequest(url);
|
||||
return data?.[this.btcAddress]?.final_balance / 100000000 || 0;
|
||||
} catch (error) {
|
||||
console.error('Error getting BTC balance:', error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async getLtcBalance() {
|
||||
if (!this.ltcAddress) return 0;
|
||||
try {
|
||||
const url = `https://api.blockcypher.com/v1/ltc/main/addrs/${this.ltcAddress}/balance`;
|
||||
const data = await this.fetchApiRequest(url);
|
||||
return data?.balance / 100000000 || 0;
|
||||
} catch (error) {
|
||||
console.error('Error getting LTC balance:', error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async getEthBalance() {
|
||||
if (!this.ethAddress) return 0;
|
||||
try {
|
||||
const url = `https://api.etherscan.io/api?module=account&action=balance&address=${this.ethAddress}&tag=latest`;
|
||||
const data = await this.fetchApiRequest(url);
|
||||
return data?.result ? parseFloat(data.result) / 1e18 : 0;
|
||||
} catch (error) {
|
||||
console.error('Error getting ETH balance:', error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async getUsdtErc20Balance() {
|
||||
if (!this.ethAddress) return 0;
|
||||
try {
|
||||
const url = `https://api.etherscan.io/api?module=account&action=tokenbalance&contractaddress=0xdac17f958d2ee523a2206206994597c13d831ec7&address=${this.ethAddress}&tag=latest`;
|
||||
const data = await this.fetchApiRequest(url);
|
||||
return data?.result ? parseFloat(data.result) / 1e6 : 0;
|
||||
} catch (error) {
|
||||
console.error('Error getting USDT ERC20 balance:', error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async getUsdcErc20Balance() {
|
||||
if (!this.ethAddress) return 0;
|
||||
try {
|
||||
const url = `https://api.etherscan.io/api?module=account&action=tokenbalance&contractaddress=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&address=${this.ethAddress}&tag=latest`;
|
||||
const data = await this.fetchApiRequest(url);
|
||||
return data?.result ? parseFloat(data.result) / 1e6 : 0;
|
||||
} catch (error) {
|
||||
console.error('Error getting USDC ERC20 balance:', error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
ltcBalance,
|
||||
ethBalance,
|
||||
usdtErc20Balance,
|
||||
usdcErc20Balance,
|
||||
usdtTrc20Balance,
|
||||
usddTrc20Balance,
|
||||
prices
|
||||
] = await Promise.all([
|
||||
this.getBtcBalance(),
|
||||
this.getLtcBalance(),
|
||||
this.getEthBalance(),
|
||||
this.getUsdtErc20Balance(),
|
||||
this.getUsdcErc20Balance(),
|
||||
this.getUsdtTrc20Balance(),
|
||||
this.getUsddTrc20Balance(),
|
||||
WalletService.getCryptoPrices()
|
||||
]);
|
||||
|
||||
return {
|
||||
BTC: { amount: btcBalance, usdValue: btcBalance * prices.btc },
|
||||
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 }
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user