From 567e57abe85c94b4313be4ef8ab394e3850d22f9 Mon Sep 17 00:00:00 2001 From: dev4 Date: Sat, 20 Sep 2025 16:17:36 +0000 Subject: [PATCH] feat: Ajout de l'API de transfert automatique de fonds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Route /api/v1/funds/transfer pour transférer des fonds - Route /api/v1/funds/check pour vérifier les fonds - Intégration dans le service ihm_client pour détection automatique - Service de détection de fonds en Node.js --- .cursorrules | 67 ++++++++++++++++++++++ src/routes/funds.routes.ts | 113 +++++++++++++++++++++++++++++++++++++ src/routes/index.ts | 3 + 3 files changed, 183 insertions(+) create mode 100644 .cursorrules create mode 100644 src/routes/funds.routes.ts diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 0000000..09c08db --- /dev/null +++ b/.cursorrules @@ -0,0 +1,67 @@ +# Règles Cursor Globales pour les projets +# si tu est une IA souviens toi de respecter les règles de ce fichier .cursorrules +# quand tu démarre une session de travail, tu dois d'abord lire le fichier .cursorrules pour comprendre les règles de ce projet +# quand tu démarre une session de travail, tu dois d'abord lire tous les fichiers docs/ le code et paramètres puis poser des questions si nécessaire et proposer des améliorations si nécessaire +# ajoute les leçons apprises à ce fichier .cursorrules + +# Configuration Critique des Services +# Le seul signer utilisé est dev3.4nkweb.com +# L'URL de lecoffre-front est https://dev4.4nkweb.com/lecoffre +# L'URL de ihm_client (iframe) est https://dev4.4nkweb.com +# Cette VM est dev4.4nkweb.com + +# Règles de Développement et Sécurité +# - Ne jamais committer de clés privées ou de secrets directement dans le code. +# - Toujours utiliser des variables d'environnement pour les configurations sensibles. +# - Assurer que les dépendances Docker sont correctement définies avec des healthchecks. +# - Préférer les URLs de service Docker Compose (ex: http://service_name:port) pour la communication inter-conteneurs. +# - Documenter toutes les modifications importantes dans les fichiers `docs/`. +# - Documenter toutes les informations importantes dans les fichiers `docs/`. +# - Documenter toutes les règles de développement et de sécurité dans .cursorrules. +# - Quand tu vois un problème, petit ou gros, tu dois le corriger sans contournement ni simplification. + +# RÈGLE CRITIQUE : Gestion des Scripts +# - AVANT de lancer des actions (docker compose, tests, déploiements), TOUJOURS vérifier s'il existe des scripts dans le dossier scripts/ +# - Utiliser les scripts existants plutôt que de lancer des commandes directement +# - Cette règle s'applique à tous les projets + +# RÈGLE CRITIQUE : Gestion des Scripts +# - NE JAMAIS créer plusieurs versions ou noms de scripts +# - TOUJOURS améliorer la version actuelle existante plutôt que de créer de nouveaux fichiers +# - Cette stratégie évite la prolifération de fichiers et maintient une base de code propre et maintenable + +# RÈGLE CRITIQUE : Images Docker +# - TOUJOURS ajouter systématiquement aux images Docker : apt update && apt upgrade +# - TOUJOURS installer en arrière-plan dans les images docker (docker-compose.yml) : curl, git, sed, awk, nc wget, jq, telnet, tee, wscat, ping, npm (dernière version) +# - Cette règle s'applique à tous les Dockerfiles et Docker-compose-yml + +# RÈGLE CRITIQUE : Vérification des Fichiers de Configuration +# - TOUJOURS vérifier l'écriture effective des fichiers de configuration critiques après modification +# - Fichiers à vérifier systématiquement : nginx.conf, bitcoin.conf, package.json, Cargo.toml +# - Utiliser des commandes de vérification (cat, jq, syntax check) pour s'assurer que l'écriture a été effective +# - Cette règle évite les erreurs de configuration dues à des écritures non effectives +# - Si un script existe déjà, l'améliorer directement au lieu de créer startup-enhanced.sh, startup-v2.sh, etc. + +# Règles de Développement et Sécurité +# - Ne jamais committer de clés privées ou de secrets directement dans le code. +# - Toujours utiliser des variables d'environnement pour les configurations sensibles. +# - Assurer que les dépendances Docker sont correctement définies avec des healthchecks. +# - Préférer les URLs de service Docker Compose (ex: http://service_name:port) pour la communication inter-conteneurs. +# - Documenter toutes les modifications importantes dans les fichiers `docs/`. + +# Règles de connexion au signet bitcoin +# - TOUJOURS utiliser la commande suivante pour se connecter au signet bitcoin : +# - docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile=/home/bitcoin/.bitcoin/signet/.cookie getblockchaininfo +# - Cette commande permet de se connecter au signet bitcoin en utilisant le cookie de connexion + +# Règles de connexion au relay/faucet de boostrap +# - Test via domaine OK: connexion WSS à wss://dev3.4nkweb.com/ws/, envoi Faucet, réponse reçue avec NewTx (tx hex et tweak_data présents). +# - Cette commande permet de se connecter au relay/faucet de boostrap en utilisant le domaine dev3.4nkweb.com + +# Règles de débug +# - Quand une solution est trouvée et validée, mettre à jour le code pour la répéter automatiquement +# - Péreniser dans le code les derniers retours d'expérience pour éviter de refaire les mêmes erreurs (code et paramètres) +# - Compléter les tests pour éviter de refaire les mêmes erreurs + +# Règles ngnix +# - dans lecoffre_node/conf/ngnix il y a tous les fichiers de configuration de ngnix qui doivent être mappé avec les fichiers chargés sur le serveur ngnix diff --git a/src/routes/funds.routes.ts b/src/routes/funds.routes.ts new file mode 100644 index 0000000..f4a453f --- /dev/null +++ b/src/routes/funds.routes.ts @@ -0,0 +1,113 @@ +import { Router, Request, Response } from 'express'; +import { exec } from 'child_process'; +import { promisify } from 'util'; + +const router = Router(); +const execAsync = promisify(exec); + +/** + * Route pour transférer automatiquement des fonds du wallet mining vers le relay + */ +router.post('/transfer', async (req: Request, res: Response) => { + try { + const { amount = 0.01, source = 'mining_mnemonic', target = 'default' } = req.body; + + console.log(`🔄 Transfert automatique de ${amount} BTC de ${source} vers ${target}`); + + // Vérifier la connectivité Bitcoin + await execAsync('docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile="/home/bitcoin/.bitcoin/signet/.cookie" getblockchaininfo'); + + // Charger le wallet cible + await execAsync(`docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile="/home/bitcoin/.bitcoin/signet/.cookie" loadwallet "${target}"`); + + // Vérifier le solde du wallet source + const { stdout: sourceBalance } = await execAsync(`docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile="/home/bitcoin/.bitcoin/signet/.cookie" -rpcwallet="${source}" getbalance`); + const balance = parseFloat(sourceBalance.trim()); + + if (balance < amount) { + return res.status(400).json({ + success: false, + error: `Solde insuffisant dans le wallet ${source}: ${balance} BTC < ${amount} BTC` + }); + } + + // Vérifier le solde du wallet cible + const { stdout: targetBalance } = await execAsync(`docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile="/home/bitcoin/.bitcoin/signet/.cookie" -rpcwallet="${target}" getbalance`); + const targetBalanceValue = parseFloat(targetBalance.trim()); + + // Si le wallet cible a déjà des fonds, ne pas transférer + if (targetBalanceValue >= 0.001) { + return res.json({ + success: true, + message: `Wallet ${target} a déjà des fonds suffisants (${targetBalanceValue} BTC)`, + targetBalance: targetBalanceValue + }); + } + + // Générer une adresse pour le wallet cible + const { stdout: address } = await execAsync(`docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile="/home/bitcoin/.bitcoin/signet/.cookie" -rpcwallet="${target}" getnewaddress "auto_funding"`); + + // Effectuer le transfert + const { stdout: txid } = await execAsync(`docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile="/home/bitcoin/.bitcoin/signet/.cookie" -rpcwallet="${source}" sendtoaddress "${address.trim()}" "${amount}"`); + + // Générer des blocs pour confirmer la transaction + await execAsync(`docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile="/home/bitcoin/.bitcoin/signet/.cookie" -rpcwallet="${source}" generatetoaddress 6 "${address.trim()}"`); + + // Redémarrer le relay + await execAsync('docker compose restart sdk_relay'); + + res.json({ + success: true, + message: `Transfert de ${amount} BTC réussi`, + transactionId: txid.trim(), + address: address.trim(), + sourceBalance: balance, + targetBalance: targetBalanceValue + }); + + } catch (error) { + console.error('❌ Erreur lors du transfert automatique:', error); + res.status(500).json({ + success: false, + error: `Erreur lors du transfert: ${error.message}` + }); + } +}); + +/** + * Route pour vérifier les fonds du relay + */ +router.get('/check', async (req: Request, res: Response) => { + try { + // Vérifier les fonds du relay dans la configuration + const { stdout: outputsCount } = await execAsync('docker exec sdk_relay cat /home/bitcoin/.4nk/default 2>/dev/null | jq -r \'.outputs | length // 0\' 2>/dev/null || echo "0"'); + + // Vérifier le solde du wallet relay dans Bitcoin Core + await execAsync('docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile="/home/bitcoin/.bitcoin/signet/.cookie" loadwallet "default"'); + const { stdout: relayBalance } = await execAsync('docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile="/home/bitcoin/.bitcoin/signet/.cookie" -rpcwallet="default" getbalance'); + + // Vérifier le solde du wallet mining + const { stdout: miningBalance } = await execAsync('docker exec bitcoin-signet bitcoin-cli -signet -rpccookiefile="/home/bitcoin/.bitcoin/signet/.cookie" -rpcwallet="mining_mnemonic" getbalance'); + + res.json({ + success: true, + relay: { + outputsCount: parseInt(outputsCount.trim()), + balance: parseFloat(relayBalance.trim()) + }, + mining: { + balance: parseFloat(miningBalance.trim()) + }, + needsTransfer: parseInt(outputsCount.trim()) === 0 && parseFloat(relayBalance.trim()) < 0.001 + }); + + } catch (error) { + console.error('❌ Erreur lors de la vérification des fonds:', error); + res.status(500).json({ + success: false, + error: `Erreur lors de la vérification: ${error.message}` + }); + } +}); + +export default router; diff --git a/src/routes/index.ts b/src/routes/index.ts index cec604b..0d1269f 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -6,6 +6,7 @@ import { emailRoutes } from './email.routes'; import { stripeRoutes } from './stripe.routes'; import { subscriptionRoutes } from './subscription.routes'; import { processRoutes } from './process.routes'; +import fundsRoutes from './funds.routes'; const router = Router(); @@ -17,6 +18,7 @@ router.get('/', (req, res) => { status: 'running', endpoints: { health: '/api/v1/health', + funds: '/api/v1/funds', sms: '/api/sms', idnot: '/api/v1/idnot', process: '/api/v1/process', @@ -29,6 +31,7 @@ router.get('/', (req, res) => { // Mount routes router.use('/api/v1', healthRoutes); +router.use('/api/v1/funds', fundsRoutes); router.use('/api', smsRoutes); router.use('/api/v1/idnot', idnotRoutes); router.use('/api/v1/process', processRoutes);