Guide de l'émetteur pour les soldes confidentiels

Émettre des tokens à soldes confidentiels sur Solana

Ce guide est destiné aux émetteurs : les équipes qui créent et exploitent un mint Token-2022 utilisant les soldes confidentiels. Il couvre les décisions prises lors de la création du mint et les opérations effectuées tout au long de sa durée de vie. Pour le flux côté détenteur (dépôt, application, transfert, retrait), consultez les pages étape par étape, et pour l'intégration de ces tokens dans un produit, consultez le Guide d'intégration.

Les soldes confidentiels maintiennent les montants des transferts et les soldes des comptes chiffrés, tout en laissant les adresses des comptes, le mint et les propriétaires publics. L'extension s'appuie sur le programme ZK ElGamal Proof pour la vérification des preuves on-chain, de sorte que le mint est utilisable sur les clusters où ce programme est activé.

Décisions prises lors de la création

L'extension de soldes confidentiels doit être initialisée avant le mint et ne peut pas être ajoutée ultérieurement. Lors de la création, vous devez décider :

  • Politique d'approbation : si les comptes peuvent opter pour les soldes confidentiels sans permission (auto) ou doivent être approuvés par l'autorité de soldes confidentiels du mint (manual).
  • Auditeur : si vous souhaitez définir une clé publique ElGamal d'auditeur global afin qu'une partie désignée puisse déchiffrer tous les montants de transfert pour le mint. Optionnel, et peut être modifié ultérieurement.
  • Extensions complémentaires optionnelles : les frais de transfert confidentiels (associés à l'extension de frais de transfert) et le mint/burn confidentiel, tous deux abordés ci-dessous. Ces extensions doivent également être initialisées lors de la création.

Créer un mint confidentiel

La CLI définit la politique d'approbation avec --enable-confidential-transfers auto ou manual ; auto permet à tout détenteur de configurer son propre compte, tandis que manual conditionne cette action à l'approbation de l'autorité de soldes confidentiels (qui correspond par défaut à l'autorité du mint). Les chemins client utilisent les mêmes paramètres via les paramètres ConfidentialTransferMint : une autorité, le flag d'approbation automatique, et une clé d'auditeur optionnelle. La politique d'approbation et l'auditeur peuvent tous deux être modifiés ultérieurement (voir Configurer un auditeur) ; seule la présence de l'extension elle-même est fixée à la création.

$ spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --enable-confidential-transfers auto

Configurer un auditeur

Un auditeur global est une clé publique ElGamal stockée sur le mint. Lorsqu'elle est définie, chaque transfert confidentiel chiffre également son montant avec cette clé, de sorte que quiconque détient la clé secrète correspondante peut déchiffrer tous les montants des transferts pour ce mint. C'est ainsi que les soldes confidentiels restent compatibles avec les exigences d'audit et de conformité : le public ne voit rien, l'auditeur voit tout.

L'autorité de soldes confidentiels peut définir, faire pivoter ou supprimer l'auditeur à tout moment. La même opération met également à jour la politique d'approbation. Sur la CLI, la clé d'auditeur est un encodage base64 d'une clé publique ElGamal ; passez --auditor-pubkey none pour la supprimer et --approve-policy auto|manual pour modifier la politique.

La rotation n'affecte que les transferts futurs. Les montants des transactions déjà enregistrées sur la blockchain restent chiffrés avec la clé d'auditeur qui était active au moment de leur exécution ; conservez donc les anciennes clés d'auditeur si vous avez besoin de déchiffrer l'historique des activités.

$ spl-token update-confidential-transfer-settings <MINT_PUBKEY> --auditor-pubkey <AUDITOR_ELGAMAL_PUBKEY>

La clé secrète de l'auditeur peut déchiffrer chaque montant de transfert pour le mint. Conservez-la avec la même rigueur qu'une clé de signature et prévoyez une rotation. Définir l'auditeur sur None désactive la visibilité des montants pour tout le monde, à l'exception des propriétaires de comptes eux-mêmes.

Approbation des comptes (politique manuelle)

Avec une politique d'approbation manuelle, un compte configuré pour les soldes confidentiels ne peut pas effectuer de transactions confidentielles tant que l'autorité de soldes confidentiels ne l'a pas approuvé. Cela donne aux émetteurs un contrôle d'accès pour les participants figurant sur liste blanche ou ayant subi une vérification KYC. La CLI n'expose pas de commande d'approbation, l'approbation s'effectue donc via un client.

token
.confidential_transfer_approve_account(
&token_account,
&authority,
&[&authority_keypair],
)
.await?;

Frais de transfert confidentiel

Si votre mint facture des frais de transfert et que les transferts sont confidentiels, les frais doivent également être retenus de manière confidentielle. L'extension ConfidentialTransferFeeConfig gère cela, et est initialisée lors de la création du mint aux côtés des extensions de frais de transfert et de soldes confidentiels.

Les frais retenus s'accumulent de façon chiffrée sur les comptes des destinataires, sont collectés vers le mint, puis retirés par l'autorité de retrait des frais retenus. Chaque montant de frais reste chiffré tout au long du processus. Rien de tout cela n'est exposé via la CLI. La clé secrète ElGamal de l'autorité de retrait des frais retenus peut déchiffrer les montants de frais retenus, ce qui, combiné aux paramètres de frais publics, peut révéler des informations sur les montants des transferts ; traitez donc cette clé comme sensible.

Initialiser la configuration des frais

Incluez ceci aux côtés de ConfidentialTransferMint et de la configuration des frais de transfert dans la même création de mint.

use spl_token_client::token::ExtensionInitializationParams;
ExtensionInitializationParams::ConfidentialTransferFeeConfig {
authority: Some(authority.pubkey().into()),
withdraw_withheld_authority_elgamal_pubkey: withdraw_withheld_elgamal_pubkey,
};

Collecter et retirer les frais retenus

La collecte déplace les frais retenus chiffrés des comptes vers le mint ; le retrait les transfère hors du mint vers un compte choisi. Deux autorités sont impliquées, et l'une ou l'autre peut différer de l'autorité du mint :

  • L'autorité des frais de transfert confidentiel (le authority défini sur ConfidentialTransferFeeConfig) active ou désactive la collecte.
  • L'autorité de retrait des frais retenus (issue de l'extension de frais de transfert TransferFeeConfig) retire les frais collectés hors du mint.

Les retraits nécessitent une preuve d'égalité et une preuve de plage, fournies en ligne ou vérifiées dans des comptes d'état de contexte.

// Permissionless: move withheld fees from accounts into the mint.
token
.confidential_transfer_harvest_withheld_tokens_to_mint(&[&source_account])
.await?;
// Withdraw withheld fees from the mint (requires the withdraw withheld authority).
token
.confidential_transfer_withdraw_withheld_tokens_from_mint(
&destination_account,
&withdraw_withheld_authority,
None, // proof context state account, supplied inline if None
None, // withheld tokens info, fetched if None
&withdraw_withheld_elgamal_keypair,
&destination_elgamal_pubkey,
&new_decryptable_available_balance,
&[&withdraw_withheld_authority_keypair],
)
.await?;

Dans le client JS, le retrait des frais collectés hors du mint (getWithdrawWithheldTokensFromMintForConfidentialTransferFeeInstruction) nécessite également une preuve d'égalité et une preuve de plage vérifiées dans des comptes d'état de contexte, et suit donc le même schéma de compte de preuve qu'un transfert confidentiel.

Mint et burn confidentiels

L'extension ConfidentialMintBurn permet à l'autorité du mint d'émettre et de brûler des jetons directement sur des soldes confidentiels, en maintenant le total en circulation chiffré. Un mint doté de cette extension désactive les chemins publics de dépôt et de retrait, car les jetons n'existent que sous forme confidentielle. Consultez la documentation du protocole pour le modèle complet.

Le mint/burn confidentiel est plus simple via le spl-token-client Rust, qui génère les preuves requises et séquence les transactions pour vous. Le client JS @solana-program/token-2022 fournit les constructeurs d'instructions bas niveau (getConfidentialMintInstruction, getConfidentialBurnInstruction, et autres) mais pas d'assistant haut niveau pour construire les preuves, et il n'existe pas de commandes CLI, donc les exemples ci-dessous sont en Rust uniquement.

Initialisez l'extension à la création du mint, puis émettez, brûlez et réconciliez l'offre au fil du temps. L'émission (minting) verse un montant chiffré dans le solde confidentiel d'un destinataire ; la destruction (burning) retire un montant chiffré vers une destruction en attente qui est ensuite intégrée à l'offre. Les deux opérations génèrent des preuves comme un transfert confidentiel.

confidential-mint-burn.rs
use spl_token_client::token::ExtensionInitializationParams;
// 1. Initialize at creation (alongside ConfidentialTransferMint).
ExtensionInitializationParams::ConfidentialMintBurn {
supply_elgamal_pubkey, // encrypts the confidential supply
decryptable_supply, // AES ciphertext of the initial supply (zero)
};
// 2. Mint an encrypted amount into a recipient's confidential balance.
token
.confidential_transfer_mint(
&mint_authority,
&destination_account,
None, // equality proof account
None, // ciphertext validity proof account
None, // range proof account
mint_amount,
&supply_elgamal_keypair,
&destination_elgamal_pubkey,
auditor_elgamal_pubkey, // Option
&supply_aes_key,
None, // supply account info, fetched if None
&[&mint_authority_keypair],
)
.await?;
// 3. Burn an encrypted amount from a holder's confidential balance into the
// mint's pending burn. Generates proofs like a confidential transfer.
token
.confidential_transfer_burn(
&owner,
&source_account,
None, // equality proof account
None, // ciphertext validity proof account
None, // range proof account
burn_amount,
&source_elgamal_keypair,
&supply_elgamal_pubkey,
auditor_elgamal_pubkey, // Option
&source_aes_key,
None, // burn account info, fetched if None
&[&owner_keypair],
)
.await?;
// 4. Fold the accumulated pending burn into the confidential supply.
token
.confidential_transfer_apply_pending_burn(&mint_authority, &[&mint_authority_keypair])
.await?;

Faites pivoter la clé de chiffrement de l'offre avec confidential_transfer_rotate_supply_elgamal_pubkey (la destruction en attente doit d'abord être nulle), et actualisez le texte chiffré de l'offre lisible avec confidential_transfer_update_decrypt_supply.

Considérations opérationnelles et de conformité

  • Garde de la clé d'auditeur. Si vous définissez un auditeur, la clé secrète de l'auditeur est une clé de déchiffrement de haute valeur. Stockez-la et faites-la pivoter avec soin, et décidez qui au sein de votre organisation (ou quel régulateur) la détient.
  • Posture de conformité. Le filtrage des adresses et l'analyse du graphe de contreparties continuent de fonctionner car les adresses restent publiques. La surveillance basée sur les montants dépend de la clé d'auditeur ou de la divulgation sélective de la part des titulaires de comptes. Définissez votre approche avant le lancement.
  • Intégration des détenteurs. La configuration d'un compte confidentiel nécessite la signature du propriétaire. Pour provisionner les comptes des utilisateurs de manière fluide, demandez-leur d'enregistrer une clé ElGamal une fois et d'utiliser le chemin de registre, décrit dans le Guide d'intégration.
  • Nombre de transactions. Un transfert confidentiel couvre actuellement plusieurs transactions dépendantes car les preuves dépassent la limite de taille de transaction actuelle. Le format de transaction v1 (déployé avec Agave v4.2) relève cette limite et devrait permettre une seule transaction on-chain.

Is this page helpful?

© 2026 Fondation Solana. Tous droits réservés.