feat: Scripts de transfert automatique de fonds
- Service Node.js de détection et transfert automatique - Scripts bash pour transfert manuel et monitoring - Documentation complète des scripts - Intégration dans docker-compose
This commit is contained in:
parent
fa13f34e0d
commit
379bd4420d
67
.cursorrules copy
Normal file
67
.cursorrules copy
Normal file
@ -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
|
@ -257,4 +257,3 @@ networks:
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.20.0.0/16
|
||||
|
||||
|
258
docker-compose.yml.backup
Normal file
258
docker-compose.yml.backup
Normal file
@ -0,0 +1,258 @@
|
||||
services:
|
||||
tor:
|
||||
image: btcpayserver/tor:0.4.8.10
|
||||
container_name: tor-proxy
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- tor
|
||||
restart: unless-stopped
|
||||
|
||||
bitcoin:
|
||||
image: git.4nkweb.com/4nk/bitcoin:latest
|
||||
container_name: bitcoin-signet
|
||||
depends_on:
|
||||
- tor
|
||||
volumes:
|
||||
- bitcoin_data:/home/bitcoin/.bitcoin
|
||||
- ./bitcoin/bitcoin.conf:/etc/bitcoin/bitcoin.conf:ro
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- bitcoin
|
||||
user: root
|
||||
entrypoint: >
|
||||
/bin/sh -c "
|
||||
chown -R bitcoin:bitcoin /home/bitcoin/.bitcoin || echo 'warn: chown partiel (fichiers bind-mount Windows)';
|
||||
exec su-exec bitcoin bitcoind -conf=/etc/bitcoin/bitcoin.conf -signet"
|
||||
healthcheck:
|
||||
test: ["CMD", "bitcoin-cli", "-conf=/etc/bitcoin/bitcoin.conf", "getblockchaininfo"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
restart: unless-stopped
|
||||
|
||||
blindbit:
|
||||
image: git.4nkweb.com/4nk/blindbit-oracle:dev
|
||||
container_name: blindbit-oracle
|
||||
depends_on:
|
||||
bitcoin:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- blindbit_data:/root/.blindbit-oracle
|
||||
- ./blindbit/blindbit.toml:/tmp/blindbit.toml:ro
|
||||
- bitcoin_data:/home/bitcoin/.bitcoin
|
||||
entrypoint: >
|
||||
sh -c "cp /tmp/blindbit.toml /root/.blindbit-oracle/blindbit.toml &&
|
||||
./main -datadir /root/.blindbit-oracle"
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- blindbit
|
||||
ports:
|
||||
- "127.0.0.1:8000:8000"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "code=$(curl -s -o /dev/null -w '%{http_code}' http://localhost:8000/tweaks/1); [ \"$$code\" != \"000\" ]"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
restart: unless-stopped
|
||||
|
||||
sdk_relay:
|
||||
image: git.4nkweb.com/4nk/sdk_relay:ext
|
||||
container_name: sdk_relay
|
||||
depends_on:
|
||||
blindbit:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ./relay/sdk_relay.conf:/home/bitcoin/.conf:ro
|
||||
- sdk_data:/home/bitcoin/.4nk
|
||||
- bitcoin_data:/home/bitcoin/.bitcoin
|
||||
ports:
|
||||
- "127.0.0.1:8090:8090"
|
||||
- "127.0.0.1:8091:8091"
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- sdk_relay
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
environment:
|
||||
- NODE_OPTIONS=--max-old-space-size=2048
|
||||
- HOME=/home/bitcoin
|
||||
- RUST_LOG=INFO
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8091/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
restart: unless-stopped
|
||||
|
||||
lecoffre-back:
|
||||
image: git.4nkweb.com/4nk/lecoffre-back-mini:ext
|
||||
container_name: lecoffre-back
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- "127.0.0.1:8080:8080"
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- lecoffre-back
|
||||
depends_on:
|
||||
sdk_relay:
|
||||
condition: service_healthy
|
||||
user: root
|
||||
entrypoint: >
|
||||
/bin/sh -lc '
|
||||
apk update && apk add --no-cache curl git wget jq busybox-extras npm coreutils && npm install -g wscat || echo "wscat installation failed"
|
||||
exec node dist/server.js
|
||||
'
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "curl -f http://localhost:8080/api/v1/health || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 60s
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
|
||||
lecoffre-front:
|
||||
image: git.4nkweb.com/4nk/lecoffre-front:ext
|
||||
container_name: lecoffre-front
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- "127.0.0.2:3004:3000"
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- lecoffre-front
|
||||
depends_on:
|
||||
lecoffre-back:
|
||||
condition: service_healthy
|
||||
user: root
|
||||
entrypoint: >
|
||||
/bin/sh -lc '
|
||||
apt-get update && apt-get install -y curl git wget jq telnet npm coreutils && npm install -g wscat || echo "wscat installation failed"
|
||||
exec node server.js
|
||||
'
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "ps aux | grep -v grep | grep next-server || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
|
||||
ihm_client:
|
||||
image: git.4nkweb.com/4nk/ihm_client:ext
|
||||
container_name: ihm_client
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- VITE_BOOTSTRAPURL=wss://dev4.4nkweb.com/ws/
|
||||
ports:
|
||||
- "127.0.0.1:3003:3003"
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- ihm_client
|
||||
depends_on:
|
||||
sdk_relay:
|
||||
condition: service_healthy
|
||||
user: root
|
||||
entrypoint: >
|
||||
/bin/sh -lc '
|
||||
apt-get update && apt-get install -y curl git wget jq telnet npm coreutils && npm install -g wscat || echo "wscat installation failed"
|
||||
exec npm start
|
||||
'
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "curl -f http://localhost:3003/ || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
|
||||
sdk_signer:
|
||||
image: git.4nkweb.com/4nk/sdk_signer:latest
|
||||
container_name: sdk_signer
|
||||
ports:
|
||||
- "127.0.0.1:3001:3001"
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- sdk_signer
|
||||
user: root
|
||||
entrypoint: >
|
||||
/bin/sh -lc '
|
||||
apk update && apk add --no-cache curl git wget jq busybox-extras npm coreutils && npm install -g wscat || echo "wscat installation failed"
|
||||
exec node /app/dist/index.js
|
||||
'
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
|
||||
sdk_storage:
|
||||
image: git.4nkweb.com/4nk/sdk_storage:ext
|
||||
container_name: sdk_storage
|
||||
ports:
|
||||
- "127.0.0.1:8081:8081"
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- sdk_storage
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=true"
|
||||
restart: unless-stopped
|
||||
|
||||
watchtower:
|
||||
image: containrrr/watchtower
|
||||
container_name: watchtower
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
command: --interval 30 --label-enable
|
||||
networks:
|
||||
- btcnet
|
||||
restart: unless-stopped
|
||||
|
||||
signet_miner:
|
||||
build:
|
||||
context: ./miner
|
||||
container_name: signet_miner
|
||||
depends_on:
|
||||
bitcoin:
|
||||
condition: service_healthy
|
||||
env_file:
|
||||
- ./miner/.env
|
||||
volumes:
|
||||
- bitcoin_data:/bitcoin:ro
|
||||
networks:
|
||||
btcnet:
|
||||
aliases:
|
||||
- signet_miner
|
||||
profiles: ["miner"]
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
bitcoin_data:
|
||||
name: 4nk_node_bitcoin_data
|
||||
blindbit_data:
|
||||
sdk_data:
|
||||
|
||||
networks:
|
||||
btcnet:
|
||||
name: 4nk_node_btcnet
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.20.0.0/16
|
171
scripts/funds/funds_detector_service.js
Executable file
171
scripts/funds/funds_detector_service.js
Executable file
@ -0,0 +1,171 @@
|
||||
#!/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;
|
23
scripts/startup-with-funds-check.sh
Executable file
23
scripts/startup-with-funds-check.sh
Executable file
@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script de démarrage avec vérification automatique des fonds
|
||||
# Usage: ./startup-with-funds-check.sh
|
||||
|
||||
set -e
|
||||
|
||||
echo "=== DÉMARRAGE AVEC VÉRIFICATION DES FONDS ==="
|
||||
|
||||
# Démarrer les services
|
||||
echo "Démarrage des services..."
|
||||
docker compose up -d
|
||||
|
||||
# Attendre que les services soient prêts
|
||||
echo "Attente du démarrage des services..."
|
||||
sleep 60
|
||||
|
||||
# Vérifier et transférer les fonds si nécessaire
|
||||
echo "Vérification des fonds..."
|
||||
./scripts/funds/check_and_transfer_funds.sh 0.001
|
||||
|
||||
echo "=== DÉMARRAGE TERMINÉ ==="
|
||||
echo "Services démarrés avec vérification des fonds automatique"
|
Loading…
x
Reference in New Issue
Block a user