Guide de l'émetteur de transferts confidentiels

Émission de tokens à transfert confidentiel sur Solana

Ce guide est destiné aux émetteurs : les équipes qui créent et exploitent un mint Token-2022 utilisant l'extension de transfert confidentiel. 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 processus côté détenteur (dépôt, application, transfert, retrait), consultez les pages pas à pas, et pour l'intégration de ces tokens dans un produit, consultez le Guide d'intégration.

Les transferts 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. Ils s'appuient sur le ZK ElGamal Proof Program 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 Confidential Transfer doit être initialisée avant que le mint ne soit initialisé et ne peut pas être ajoutée ultérieurement. Lors de la création, vous décidez :

  • Politique d'approbation : si les comptes peuvent opter pour les transferts confidentiels sans permission (auto) ou doivent être approuvés par l'autorité de transfert confidentiel 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 cela à une approbation de l'autorité de transfert confidentiel (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é, l'indicateur d'approbation automatique, et une clé d'auditeur optionnelle. La politique d'approbation et l'auditeur peuvent être modifiés ultérieurement (voir Configurer un auditeur) ; seule la présence de l'extension elle-même est fixée lors de 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 sous cette clé, de sorte que quiconque détient la clé secrète correspondante peut déchiffrer tous les montants de transfert pour le mint. C'est ainsi que les transferts confidentiels restent compatibles avec les exigences d'audit et de conformité : le public ne voit rien, l'auditeur voit tout.

L'autorité de transfert confidentiel peut définir, faire pivoter ou supprimer l'auditeur à tout moment. La même opération met également à jour la politique d'approbation. Dans la CLI, la clé de l'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 transferts confidentiels ne peut pas effectuer de transactions confidentielles tant que l'autorité de transfert confidentiel ne l'a pas approuvé. Cela offre aux émetteurs un contrôle d'accès pour les participants figurant sur liste blanche ou ayant passé 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 applique 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, conjointement avec les extensions de frais de transfert et de transfert confidentiel.

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.