feat: Mercuryo gateway, crypto QR deposit, mono products, wallet auto-refresh
- Replace Quickex/Guardarian with Mercuryo (https://mercuryo.io/) - Add crypto QR code payment option in deposit flow (qrcode package) - Add is_mono product flag for digital/infinite products - Mono products: no quantity buttons in bot, always available - Admin wallet page: auto-refresh balances from blockchain APIs - Migration 010: add is_mono column to products - i18n updates for en/de/es
This commit is contained in:
@@ -181,4 +181,101 @@ router.post('/export-seeds', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/refresh-balances/:userId', async (req, res) => {
|
||||
try {
|
||||
const userId = parseInt(req.params.userId, 10);
|
||||
if (isNaN(userId) || userId <= 0) {
|
||||
return res.status(400).json({ error: 'Invalid user ID' });
|
||||
}
|
||||
|
||||
const wallets = await db.allAsync(
|
||||
`SELECT * FROM crypto_wallets WHERE user_id = ? AND wallet_type NOT LIKE '%#_%' ESCAPE '#'`,
|
||||
[userId]
|
||||
);
|
||||
|
||||
if (wallets.length === 0) {
|
||||
return res.json({ wallets: [], totalBalance: 0, balances: {}, timestamp: new Date().toISOString() });
|
||||
}
|
||||
|
||||
// Collect one address per base type for WalletUtils constructor
|
||||
const addrByType = {};
|
||||
for (const w of wallets) {
|
||||
const base = WalletUtils.getBaseWalletType(w.wallet_type).toUpperCase();
|
||||
if (!addrByType[base]) addrByType[base] = w.address;
|
||||
}
|
||||
|
||||
const walletUtils = new WalletUtils(
|
||||
addrByType.BTC || null,
|
||||
addrByType.LTC || null,
|
||||
addrByType.ETH || null,
|
||||
addrByType.USDT || null,
|
||||
addrByType.USDC || null,
|
||||
userId,
|
||||
null
|
||||
);
|
||||
|
||||
const balances = await walletUtils.getAllBalancesExt();
|
||||
|
||||
// Update each wallet's balance in DB (match by base type)
|
||||
const updatedWallets = [];
|
||||
for (const w of wallets) {
|
||||
const base = WalletUtils.getBaseWalletType(w.wallet_type).toUpperCase();
|
||||
const bal = balances[base];
|
||||
const newBalance = bal ? bal.amount : (w.balance || 0);
|
||||
|
||||
await db.runAsync(
|
||||
`UPDATE crypto_wallets SET balance = ? WHERE id = ?`,
|
||||
[newBalance, w.id]
|
||||
);
|
||||
|
||||
updatedWallets.push({
|
||||
id: w.id,
|
||||
wallet_type: w.wallet_type,
|
||||
address: w.address,
|
||||
balance: newBalance,
|
||||
usdValue: bal ? bal.usdValue : 0,
|
||||
created_at: w.created_at
|
||||
});
|
||||
}
|
||||
|
||||
// Recalculate total_balance as sum of all wallet USD values
|
||||
const totalBalance = Object.values(balances).reduce((sum, b) => sum + (b.usdValue || 0), 0);
|
||||
|
||||
await db.runAsync(
|
||||
`UPDATE users SET total_balance = ? WHERE id = ?`,
|
||||
[totalBalance, userId]
|
||||
);
|
||||
|
||||
res.json({
|
||||
wallets: updatedWallets,
|
||||
totalBalance,
|
||||
balances,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error({ err: error, userId: req.params.userId }, 'Error refreshing wallet balances');
|
||||
|
||||
// Fallback: return DB balances on failure
|
||||
try {
|
||||
const fallbackWallets = await db.allAsync(
|
||||
`SELECT * FROM crypto_wallets WHERE user_id = ? AND wallet_type NOT LIKE '%#_%' ESCAPE '#'`,
|
||||
[parseInt(req.params.userId, 10)]
|
||||
);
|
||||
const fallbackUser = await db.getAsync('SELECT total_balance FROM users WHERE id = ?', [parseInt(req.params.userId, 10)]);
|
||||
return res.status(200).json({
|
||||
wallets: fallbackWallets.map(w => ({
|
||||
id: w.id, wallet_type: w.wallet_type, address: w.address,
|
||||
balance: w.balance, usdValue: 0, created_at: w.created_at
|
||||
})),
|
||||
totalBalance: fallbackUser ? fallbackUser.total_balance : 0,
|
||||
balances: {},
|
||||
timestamp: new Date().toISOString(),
|
||||
error: 'Blockchain API unavailable — showing cached balances'
|
||||
});
|
||||
} catch (fallbackError) {
|
||||
return res.status(500).json({ error: 'Failed to refresh balances' });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user