如何创建带有机密转账扩展的 mint
机密转账扩展通过向 mint account 添加额外状态来实现私密代币转账。本节介绍如何创建启用了此扩展的 token mint。
下图展示了创建带有机密转账扩展的 mint 所涉及的步骤:
机密转账 Mint 状态
该扩展将 ConfidentialTransferMint 状态添加到 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,}
ConfidentialTransferMint 包含三个配置字段:
-
authority:有权更改 mint 的机密转账设置,并在未启用自动审批时批准新机密账户的账户。
-
auto_approve_new_accounts:设置为 true 时,用户可以默认创建启用机密转账的 token account。设置为 false 时,authority 必须在每个新 token account 用于机密转账之前对其进行审批。
-
auditor_elgamal_pubkey:一个可选的审计方,能够解密机密交易中的转账金额,在保护公众隐私的同时提供合规机制。
所需指令
创建启用了机密转账的 mint 需要在单笔交易中包含三条指令:
-
创建 Mint Account:调用 System Program 的
CreateAccount指令以创建 mint account。 -
初始化机密转账扩展:调用 Token Extensions Program 的 ConfidentialTransferInstruction::InitializeMint 指令,为 mint 配置
ConfidentialTransferMint状态。 -
初始化 Mint:调用 Token Extensions Program 的
Instruction::InitializeMint指令以初始化标准 mint 状态。
虽然您可以手动编写这些指令,但 spl_token_client crate 提供了 create_mint
方法,可在单次函数调用中构建并发送包含全部三条指令的交易,如下方示例所示。
示例代码
以下代码演示了如何使用机密转账扩展创建铸币。
机密转账依赖于 ZK ElGamal 证明程序,该程序已在主网和开发网上启用。标准的
solana-test-validator 不会启用它,但主网分叉本地 validator(例如
Surfpool)会启用。请使用已充值的付款账户在上述环境之一中运行示例(代码默认使用开发网),并将占位符铸币地址和账户地址替换为您自己的地址。
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?