#!/usr/bin/env node /** * Service de détection et transfert automatique de fonds * Ce service surveille les applications et transfère automatiquement des fonds * quand un manque de fonds est détecté */ const { spawn, exec } = require('child_process'); const fs = require('fs'); const path = require('path'); class FundsDetectorService { constructor() { this.isRunning = false; this.checkInterval = 30000; // 30 secondes this.minFundsThreshold = 0.001; // 0.001 BTC = 100,000 sats this.transferAmount = 0.01; // 0.01 BTC = 1,000,000 sats this.logFile = '/tmp/funds_detector.log'; } log(message) { const timestamp = new Date().toISOString(); const logMessage = `[${timestamp}] ${message}\n`; console.log(logMessage.trim()); fs.appendFileSync(this.logFile, logMessage); } async checkRelayFunds() { try { // Vérifier les fonds du relay dans la configuration const outputsCount = await this.getRelayOutputsCount(); this.log(`Relay outputs count: ${outputsCount}`); // Vérifier le solde du wallet relay dans Bitcoin Core const relayBalance = await this.getRelayBalance(); this.log(`Relay balance: ${relayBalance} BTC`); // Si le relay n'a pas de fonds, déclencher le transfert if (outputsCount === 0 && parseFloat(relayBalance) < this.minFundsThreshold) { this.log(`⚠️ Fonds insuffisants détectés. Lancement du transfert automatique...`); await this.transferFunds(); return true; } this.log(`✅ Fonds suffisants (outputs: ${outputsCount}, balance: ${relayBalance} BTC)`); return false; } catch (error) { this.log(`❌ Erreur lors de la vérification des fonds: ${error.message}`); return false; } } async getRelayOutputsCount() { return new Promise((resolve, reject) => { exec('docker exec sdk_relay cat /home/bitcoin/.4nk/default 2>/dev/null | jq -r \'.outputs | length // 0\' 2>/dev/null || echo "0"', (error, stdout, stderr) => { if (error) { reject(error); } else { resolve(parseInt(stdout.trim()) || 0); } }); }); } async getRelayBalance() { return new Promise((resolve, reject) => { exec('docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile="/home/bitcoin/.bitcoin/signet/.cookie" -rpcwallet="default" getbalance 2>/dev/null || echo "0"', (error, stdout, stderr) => { if (error) { reject(error); } else { resolve(parseFloat(stdout.trim()) || 0); } }); }); } async transferFunds() { try { this.log(`🔄 Transfert de ${this.transferAmount} BTC...`); // Charger le wallet relay await this.execCommand('docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile="/home/bitcoin/.bitcoin/signet/.cookie" loadwallet "default" > /dev/null 2>&1 || true'); // Générer une adresse pour le relay const relayAddress = await this.execCommand('docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile="/home/bitcoin/.bitcoin/signet/.cookie" -rpcwallet="default" getnewaddress "relay_funding" 2>/dev/null'); this.log(`Adresse générée: ${relayAddress}`); // Effectuer le transfert const txid = await this.execCommand(`docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile="/home/bitcoin/.bitcoin/signet/.cookie" -rpcwallet="mining_mnemonic" sendtoaddress "${relayAddress}" "${this.transferAmount}" 2>/dev/null`); this.log(`Transaction ID: ${txid}`); // Générer des blocs pour confirmer await this.execCommand(`docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile="/home/bitcoin/.bitcoin/signet/.cookie" -rpcwallet="mining_mnemonic" generatetoaddress 6 "${relayAddress}" > /dev/null 2>&1`); // Redémarrer le relay this.log(`🔄 Redémarrage du relay...`); await this.execCommand('docker compose restart sdk_relay'); this.log(`✅ Transfert de fonds réussi et relay redémarré`); return true; } catch (error) { this.log(`❌ Erreur lors du transfert: ${error.message}`); return false; } } async execCommand(command) { return new Promise((resolve, reject) => { exec(command, (error, stdout, stderr) => { if (error) { reject(error); } else { resolve(stdout.trim()); } }); }); } async start() { if (this.isRunning) { this.log('Service déjà en cours d\'exécution'); return; } this.isRunning = true; this.log('🚀 Démarrage du service de détection des fonds'); this.log(`Seuil minimum: ${this.minFundsThreshold} BTC`); this.log(`Montant de transfert: ${this.transferAmount} BTC`); this.log(`Intervalle de vérification: ${this.checkInterval / 1000} secondes`); const checkLoop = async () => { if (!this.isRunning) return; try { await this.checkRelayFunds(); } catch (error) { this.log(`❌ Erreur dans la boucle de vérification: ${error.message}`); } setTimeout(checkLoop, this.checkInterval); }; // Démarrer la boucle de vérification checkLoop(); } stop() { this.isRunning = false; this.log('🛑 Arrêt du service de détection des fonds'); } } // Gestion des signaux pour un arrêt propre process.on('SIGINT', () => { console.log('\n🛑 Arrêt du service...'); process.exit(0); }); process.on('SIGTERM', () => { console.log('\n🛑 Arrêt du service...'); process.exit(0); }); // Démarrer le service si ce script est exécuté directement if (require.main === module) { const service = new FundsDetectorService(); service.start(); } module.exports = FundsDetectorService;