Cómo crear un mint con la extensión Confidential Transfer
La extensión Confidential Transfer permite transferencias privadas de tokens añadiendo estado adicional al mint account. Esta sección explica cómo crear un token mint con esta extensión habilitada.
El siguiente diagrama muestra los pasos necesarios para crear un mint con la extensión Confidential Transfer:
Estado del Mint con Confidential Transfer
La extensión añade el estado ConfidentialTransferMint al mint account:
#[repr(C)]#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]pub struct ConfidentialTransferMint {/// Authority to modify the `ConfidentialTransferMint` configuration and to/// approve new accounts (if `auto_approve_new_accounts` is true)////// The legacy Token Multisig account is not supported as the authoritypub authority: OptionalNonZeroPubkey,/// Indicate if newly configured accounts must be approved by the/// `authority` before they may be used by the user.////// * If `true`, no approval is required and new accounts may be used/// immediately/// * If `false`, the authority must approve newly configured accounts (see/// `ConfidentialTransferInstruction::ConfigureAccount`)pub auto_approve_new_accounts: PodBool,/// Authority to decode any transfer amount in a confidential transfer.pub auditor_elgamal_pubkey: OptionalNonZeroElGamalPubkey,}
El ConfidentialTransferMint contiene tres campos de configuración:
-
authority: La cuenta que tiene permiso para cambiar la configuración de transferencias confidenciales del mint y aprobar nuevas cuentas confidenciales si la aprobación automática está deshabilitada.
-
auto_approve_new_accounts: Cuando se establece en true, los usuarios pueden crear token accounts con transferencias confidenciales habilitadas de forma predeterminada. Cuando es false, la authority debe aprobar cada nuevo token account antes de que pueda utilizarse para transferencias confidenciales.
-
auditor_elgamal_pubkey: Un auditor opcional que puede descifrar los montos de transferencia en transacciones confidenciales, proporcionando un mecanismo de cumplimiento normativo mientras se mantiene la privacidad frente al público en general.
Instrucciones Requeridas
Crear un mint con Confidential Transfer habilitado requiere tres instrucciones en una única transacción:
-
Crear el Mint Account: Invocar la instrucción
CreateAccountdel System Program para crear el mint account. -
Inicializar la Extensión Confidential Transfer: Invocar la instrucción ConfidentialTransferInstruction::InitializeMint del Token Extensions Program para configurar el estado
ConfidentialTransferMintdel mint. -
Inicializar el Mint: Invocar la instrucción
Instruction::InitializeMintdel Token Extensions Program para inicializar el estado estándar del mint.
Si bien es posible escribir estas instrucciones manualmente, el crate
spl_token_client proporciona un método create_mint que construye y envía una
transacción con las tres instrucciones en una única llamada a función, como se
muestra en el ejemplo a continuación.
Código de ejemplo
El siguiente código demuestra cómo crear un mint con la extensión Confidential Transfer.
Las transferencias confidenciales dependen del programa ZK ElGamal Proof, que
está habilitado en mainnet y devnet. Un solana-test-validator estándar no lo
habilita, pero un validator local con bifurcación de mainnet como
Surfpool sí lo hace. Ejecuta el ejemplo en uno de ellos
(el código usa devnet) con un pagador con fondos, y reemplaza las direcciones de
mint y cuenta de marcador de posición con las tuyas propias.
Rust
fn main() -> Result<()> {let rpc_client = RpcClient::new_with_commitment(String::from("https://api.devnet.solana.com"),CommitmentConfig::confirmed(),);let payer = load_keypair()?;let mint = Keypair::new();let decimals: u8 = 2;// Allocate space for a mint that carries the ConfidentialTransferMint// extension, then fund it for rent exemption.let space =ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::ConfidentialTransferMint])?;let rent = rpc_client.get_minimum_balance_for_rent_exemption(space)?;// The auditor ElGamal key lets the issuer decrypt transfer amounts for// compliance. Persist this key. Pass `None` to create a mint with no auditor.let auditor = ElGamalKeypair::new_rand();let auditor_pubkey: PodElGamalPubkey = (*auditor.pubkey()).into();let create_account_ix = system_instruction::create_account(&payer.pubkey(),&mint.pubkey(),rent,space as u64,&spl_token_2022::id(),);// The confidential-transfer extension must be initialized before the base// mint and cannot be added later.let init_confidential_ix = initialize_confidential_transfer_mint(&spl_token_2022::id(),&mint.pubkey(),Some(payer.pubkey()), // authority that can update confidential settingstrue, // auto-approve new accountsSome(auditor_pubkey),)?;let init_mint_ix = initialize_mint_base(&spl_token_2022::id(),&mint.pubkey(),&payer.pubkey(), // mint authorityNone, // freeze authoritydecimals,)?;let blockhash = rpc_client.get_latest_blockhash()?;let transaction = Transaction::new_signed_with_payer(&[create_account_ix, init_confidential_ix, init_mint_ix],Some(&payer.pubkey()),&[&payer, &mint],blockhash,);let signature = rpc_client.send_and_confirm_transaction(&transaction)?;println!("Created confidential mint {}: {signature}", mint.pubkey());Ok(())}fn load_keypair() -> Result<Keypair> {let keypair_path = dirs::home_dir().context("could not find home directory")?.join(".config/solana/id.json");let bytes: Vec<u8> = serde_json::from_reader(std::fs::File::open(keypair_path)?)?;let mut secret = [0u8; 32];secret.copy_from_slice(&bytes[0..32]);Ok(Keypair::new_from_array(secret))}
Typescript
const client = await createClient().use(signerFromFile(join(homedir(), ".config/solana/id.json"))).use(solanaRpc({rpcUrl: "https://api.devnet.solana.com"}));const payer = client.payer;const mint = await generateKeyPairSigner();// The auditor ElGamal key lets the issuer decrypt transfer amounts for// compliance. Persist it; omit `auditorElgamalPubkey` to create a mint with no// auditor.const auditor = await deriveElGamalKeypairForOwnerMint({signer: payer,owner: payer.address,mint: mint.address});const plan = getCreateMintInstructionPlan({payer,newMint: mint,decimals: 2,mintAuthority: payer,extensions: [{__kind: "ConfidentialTransferMint",authority: some(payer.address),autoApproveNewAccounts: true,auditorElgamalPubkey: some(auditor.elgamalPubkey)}]});const result = await client.sendTransaction(plan);console.log(`Created confidential mint ${mint.address}: ${result.context.signature}`);
Is this page helpful?