Qu'est-ce qu'un opérateur Private Channels ?
Un opérateur est une entité de confiance, autorisée on-chain, qui fait le lien entre Solana
Mainnet et le réseau de canaux privés. Les opérateurs sont provisionnés par
l'administrateur de l'instance via AddOperator, qui crée un PDA Operator on-chain ;
sans cela, aucune partie ne peut appeler ReleaseFunds. En pratique, un opérateur est une
organisation ou une équipe qui fait tourner les services chargés de surveiller les dépôts, de minter
les tokens côté canal, de détecter les retraits et de régler les fonds sur Mainnet.
Exploiter une instance offre à vos utilisateurs des transferts privés et à haut volume qui n'apparaissent
pas sur Solana Mainnet, un débit instantané sans frais au-delà du TPS natif de Solana,
et un accès contrôlé via RBAC.
Si vous êtes un développeur qui intègre une instance Private Channels existante plutôt que d'en déployer une, commencez plutôt par le Démarrage rapide.
Avant de commencer
Prérequis
Épinglez ces versions sur l'hôte pour correspondre aux images Docker :
- Docker Engine 26+ (macOS Apple Silicon : activer « Docker VMM » dans Paramètres -> Options de machine virtuelle)
- Node.js 24.7.0 et pnpm 10.15.1
- Solana CLI 3.1.13 (Agave)
- Rust 1.91.0
- Un endpoint Yellowstone gRPC pour Devnet (disponible chez Helius, Triton, QuickNode)
Pour les exigences réseau et les assignations de ports par défaut, consultez
docs/TECHNICAL_REQUIREMENTS.md
dans le dépôt.
Installez la chaîne d'outils Solana épinglée et préchauffez le cache SBF :
make install-toolchain
Services
Exploiter une instance Private Channels implique de prendre en charge cinq responsabilités permanentes, chacune gérée par des conteneurs dédiés dans la pile Docker Compose :
- Indexer Mainnet pour les dépôts -
indexer-solanasurveille Solana Mainnet pour les événementsDepositvia Yellowstone gRPC ;operator-solanarécupère les dépôts confirmés et minte le solde de tokens équivalent sur le réseau de canaux - Indexer le canal pour les retraits -
indexer-private-channelinterroge le canal toutes les secondes pour les événements de burnWithdrawFundset enregistre les retraits en attente dans la base de données - Libérer les fonds sur Mainnet -
operator-private-channelrécupère les enregistrements en attente et appelleReleaseFundssur l'Escrow Program avec une preuve d'exclusion SMT valide - Gérer la racine SMT -
operator-private-channelappelleResetSmtRootautomatiquement lors de la rotation des epoch de l'arbre ; la vérification on-chainverify_smt_exclusion_proofest la dernière ligne de défense contre les retraits non autorisés - Faire tourner la passerelle et le service d'authentification - la passerelle est le seul point
d'entrée public pour tout le trafic client ; le service d'authentification (optionnel) applique
JWT/RBAC lorsque
JWT_SECRETest défini
Pour l'inventaire complet des services et les assignations de ports, consultez la Référence de configuration.
Note de sécurité : Les ports des nœuds d'écriture et de lecture sont liés uniquement à la boucle locale (
127.0.0.1), mais plusieurs autres services (passerelle, auth, métriques opérateur, Grafana, Prometheus, cAdvisor) sont publiés sur toutes les interfaces réseau par défaut. Consultez la Référence de configuration pour le tableau complet des ports et protégez-les par un pare-feu avant tout déploiement public. Le RBAC ne couvre que les méthodes JSON-RPC propres à la passerelle, pas ces autres services.
Contrôle d'accès : Ouvert vs. RBAC
Par défaut, la passerelle accepte toutes les connexions ; aucun token requis. Pour activer
le RBAC basé sur JWT, définissez JWT_SECRET et démarrez la pile avec --profile auth. Consultez
Authentification & Rôles pour la
référence de configuration complète, notamment comment provisionner le rôle operator et
enregistrer les wallets des utilisateurs.
Si vous activez l'authentification, ajoutez ces éléments à votre environnement avant de démarrer la pile :
JWT_SECRET=<openssl rand -hex 32> # must match on gateway and auth serviceAUTH_PORT=8903
Configuration de l'environnement
.env.devnet est déjà suivi dans le dépôt avec les valeurs par défaut spécifiques au devnet
déjà renseignées ; modifiez-le directement plutôt que de le régénérer depuis .env.example,
ce qui écraserait ces valeurs par défaut.
Renseignez les valeurs restantes au fur et à mesure des étapes de déploiement ci-dessous ; certaines
ne sont disponibles qu'en cours de déploiement. Les secrets vont dans le fichier .env ignoré par git ;
les variables non secrètes vont dans .env.devnet.
Secrets - à définir immédiatement :
POSTGRES_PASSWORD=<openssl rand -hex 32>POSTGRES_REPLICATION_PASSWORD=<openssl rand -hex 32>
Variables obtenues pendant le déploiement :
ESCROW_INSTANCE_ID=<instance address - from Step 3>ADMIN_PRIVATE_KEY=<operator keypair as u8 array or base58 - from Step 4>DEVNET_RPC_URL=https://api.devnet.solana.comDEVNET_YELLOWSTONE_ENDPOINT=<your Yellowstone gRPC endpoint>INDEXER_YELLOWSTONE_TOKEN=<your Yellowstone auth token>
ADMIN_PRIVATE_KEY est le signataire payeur de frais requis par les services off-chain,
sans rapport avec l'administrateur d'instance on-chain de l'étape 3. Ce guide place le
keypair de l'opérateur généré à l'étape 4 ci-dessous dans ADMIN_PRIVATE_KEY et
laisse l'OPERATOR_PRIVATE_KEY optionnel non défini, de sorte que le signataire opérateur utilise
la même clé en repli. Ne mettez jamais le keypair d'administrateur d'instance au niveau du protocole de
l'étape 3 dans l'une ou l'autre variable.
Pour la référence complète des variables d'environnement, consultez Configuration.
Déploiement
Construire les images
make docker-devnet-build
Ceci compile tous les services Rust dans une image Docker partagée. La première construction prend entre 30 minutes et une heure.
Configurer l'interface d'administration
L'interface d'administration est un outil basé sur navigateur pour créer et configurer l'instance d'escrow :
un utilitaire de développement et d'administration, et non un produit destiné aux utilisateurs
finaux ni un composant d'exécution obligatoire. Toutes les opérations qu'il effectue
(CreateInstance, AllowMint, AddOperator) peuvent également être exécutées via les scripts CLI
du dépôt.
cd admin-uipnpm installecho "PRIVATE_CHANNEL_RPC_URL=http://localhost:8899" > .envpnpm dev # opens at http://localhost:5173
Créer une instance d'escrow
- Configurez votre wallet de navigateur sur Devnet et assurez-vous d'avoir du SOL Devnet pour les frais
- Dans l'interface d'administration, cliquez sur Créer une nouvelle instance et approuvez la transaction
- Copiez l'adresse de l'instance et définissez-la comme
ESCROW_INSTANCE_IDdans.env.devnet
Alternativement, utilisez le script CLI :
cargo run --bin create_instance -- https://api.devnet.solana.com ./keypairs/admin.json
Générer un keypair d'opérateur
solana-keygen new -o operator-keypair.json -s --no-bip39-passphrasesolana-keygen pubkey operator-keypair.json
Définissez le contenu du keypair comme ADMIN_PRIVATE_KEY dans votre environnement. La clé
publique n'est pas une variable d'environnement ; vous la passerez directement comme
pubkey de l'opérateur à l'étape « Configurer l'instance » ci-dessous.
Finaliser les variables d'environnement
Mettez à jour .env.devnet avec ESCROW_INSTANCE_ID, DEVNET_RPC_URL,
DEVNET_YELLOWSTONE_ENDPOINT et INDEXER_YELLOWSTONE_TOKEN. Placez les secrets
(POSTGRES_PASSWORD, POSTGRES_REPLICATION_PASSWORD, ADMIN_PRIVATE_KEY) dans
le fichier .env ignoré par git.
Si vous avez décidé d'activer le RBAC
(Contrôle d'accès : Ouvert vs. RBAC), ajoutez également
JWT_SECRET et AUTH_PORT maintenant.
Démarrer tous les services
Sans authentification :
make docker-devnet-up
Avec authentification :
docker compose -f docker-compose.devnet.yml --env-file versions.env --env-file .env.devnet --env-file .env --profile auth up -d
Compose désactive son chargement automatique de .env dès qu'un flag --env-file est
passé, donc le --env-file .env final est obligatoire. Sans lui,
POSTGRES_PASSWORD, ADMIN_PRIVATE_KEY et JWT_SECRET (que vous avez placés dans
.env ci-dessus) se retrouvent vides et la pile ne démarre pas correctement.
Démarrez les services avant de configurer l'instance. L'indexeur diffuse les événements en temps réel, donc lancer la pile en premier garantit que
AllowMintet votre premier dépôt sont indexés dans l'ordre sans nécessiter de rattrapage.
Configurer l'instance
Avec la pile en cours d'exécution, autorisez un mint de token et ajoutez votre opérateur via l'interface d'administration :
- Autoriser le Mint : Fonctions d'administration -> Gestion des Mints -> saisir l'adresse du mint -> Autoriser le Mint
- Ajouter un opérateur : Fonctions d'administration -> Gestion des opérateurs -> saisir la pubkey de l'opérateur -> Ajouter un opérateur
Ou via CLI :
cargo run --bin add_operator -- \https://api.devnet.solana.com \./keypairs/admin.json \<INSTANCE_ID> \<OPERATOR_PUBKEY>
Ce guide cible le devnet Solana. Pour Mainnet :
- Les IDs de programme sont compilés via
declare_id!(): vérifiez que vous utilisez les bons IDs Mainnet du dépôt - Les endpoints Yellowstone gRPC nécessitent un abonnement Mainnet ; les endpoints devnet ne diffuseront pas les événements Mainnet
- Le wallet de l'opérateur paie des frais en SOL pour chaque appel à
ReleaseFunds, donc calibrez le solde SOL en fonction de votre volume de retraits attendu - Changez toutes les identifiants par défaut (Grafana, PostgreSQL) avant tout déploiement public
Opérations
Commandes utiles
# View logs (all services)make docker-devnet-logs# View logs (specific service)docker compose -f docker-compose.devnet.yml --env-file versions.env --env-file .env.devnet logs -f indexer-solana# Stop servicesmake docker-devnet-down# Stop and wipe all state (volumes)make docker-devnet-clean
Observabilité
La pile inclut Prometheus, Grafana et cAdvisor pour les métriques et la surveillance des conteneurs. Grafana est accessible sur le port 37429.
Le mot de passe Grafana par défaut est admin. Changez-le avant d'exposer le port 37429
à tout réseau au-delà de localhost.
Dépannage
Le solde du canal ne se met pas à jour après un dépôt
- Confirmez que la transaction de dépôt Mainnet a bien été enregistrée sur un explorateur Mainnet
- Vérifiez que
indexer-solanaest en cours d'exécution :docker compose -f docker-compose.devnet.yml --env-file versions.env --env-file .env.devnet logs -f indexer-solana - Vérifiez que
operator-solanaest en cours d'exécution :docker compose -f docker-compose.devnet.yml --env-file versions.env --env-file .env.devnet logs -f operator-solana - Vérifiez que votre endpoint Yellowstone gRPC est accessible et que le token est valide
(
DEVNET_YELLOWSTONE_ENDPOINT,INDEXER_YELLOWSTONE_TOKEN) - Attendez jusqu'à 30 secondes après la confirmation on-chain, car l'indexeur applique un délai de sécurité de finalité avant de créditer
Le retrait ne se règle pas sur Mainnet
- Vérifiez que
indexer-private-channelest en cours d'exécution :docker compose -f docker-compose.devnet.yml --env-file versions.env --env-file .env.devnet logs -f indexer-private-channel - Vérifiez que
operator-private-channelest en cours d'exécution :docker compose -f docker-compose.devnet.yml --env-file versions.env --env-file .env.devnet logs -f operator-private-channel - Confirmez que le keypair de l'opérateur dans
ADMIN_PRIVATE_KEYcorrespond à la clé enregistrée avecAddOperatoron-chain - Si les logs affichent « SMT root mismatch », le service s'arrête plutôt que de soumettre une preuve invalide. Arrêtez la pile, restaurez depuis un état cohérent et redémarrez
Échecs d'authentification JWT (401 sur toutes les requêtes)
- Confirmez que
JWT_SECRETest identique sur les conteneurs de la passerelle et du service d'authentification - Confirmez que la pile a été démarrée avec
--profile auth - Les tokens expirent après 24 heures ; authentifiez-vous à nouveau pour obtenir un token valide
La première construction prend trop de temps
C'est normal. Le premier make docker-devnet-build compile tous les services Rust et
peut prendre 30 à 60 minutes sur du matériel standard. Les constructions suivantes utilisent le cache
de couches Docker et sont nettement plus rapides.
Étapes suivantes
Démarrage rapide
Testez votre déploiement : dépôt, transfert et retrait sur devnet.
Configuration
Référence complète des variables d'environnement pour tous les services.
Authentification & Rôles
Configurez l'authentification JWT et provisionnez les utilisateurs avec le rôle opérateur.
Instructions
Référence complète de toutes les instructions on-chain.
Is this page helpful?