토큰 민트 생성

Confidential Transfer 확장으로 mint를 생성하는 방법

Confidential Transfer 확장은 mint account에 추가 상태를 더해 프라이빗 토큰 전송을 가능하게 합니다. 이 섹션에서는 이 확장이 활성화된 토큰 mint를 생성하는 방법을 설명합니다.

다음 다이어그램은 Confidential Transfer 확장으로 mint를 생성하는 데 필요한 단계를 보여줍니다:

Create Mint with Confidential Transfer Extension

Confidential Transfer Mint 상태

이 확장은 mint account에 ConfidentialTransferMint 상태를 추가합니다:

Confidential Mint State
#[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 authority
pub 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,
}

*rsConfidentialTransferMint*에는 세 가지 구성 필드가 있습니다:

  • authority: mint의 기밀 전송 설정을 변경하고, 자동 승인이 비활성화된 경우 새로운 기밀 계정을 승인할 권한을 가진 계정입니다.

  • auto_approve_new_accounts: true로 설정하면 사용자가 기밀 전송이 기본적으로 활성화된 token account를 생성할 수 있습니다. false로 설정하면 authority가 각 새 token account를 기밀 전송에 사용하기 전에 승인해야 합니다.

  • auditor_elgamal_pubkey: 기밀 트랜잭션에서 전송 금액을 복호화할 수 있는 선택적 감사자로, 일반 대중으로부터 프라이버시를 유지하면서 규정 준수 메커니즘을 제공합니다.

필수 명령어

Confidential Transfer가 활성화된 mint를 생성하려면 단일 트랜잭션에서 세 가지 명령어가 필요합니다:

  1. Mint Account 생성: System Program의 CreateAccount 명령어를 호출하여 mint account를 생성합니다.

  2. Confidential Transfer 확장 초기화: Token Extensions Program의 ConfidentialTransferInstruction::InitializeMint 명령어를 호출하여 mint의 ConfidentialTransferMint 상태를 구성합니다.

  3. Mint 초기화: Token Extensions Program의 Instruction::InitializeMint 명령어를 호출하여 표준 mint 상태를 초기화합니다.

이러한 명령어를 직접 작성할 수도 있지만, spl_token_client 크레이트는 아래 예제에서 보여주듯이 단일 함수 호출로 세 가지 명령어를 모두 포함한 트랜잭션을 빌드하고 전송하는 create_mint 메서드를 제공합니다.

예제 코드

다음 코드는 Confidential Transfer 확장을 사용하여 민트를 생성하는 방법을 보여줍니다.

Confidential Transfer는 메인넷과 데브넷에서 활성화된 ZK ElGamal Proof 프로그램에 의존합니다. 기본 solana-test-validator는 이를 활성화하지 않지만, Surfpool과 같은 메인넷 포킹 로컬 validator는 활성화합니다. 자금이 충전된 페이어를 사용하여 해당 환경 중 하나(코드는 데브넷을 사용)에서 예제를 실행하고, 플레이스홀더 민트 및 계정 주소를 본인의 것으로 교체하세요.

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 settings
true, // auto-approve new accounts
Some(auditor_pubkey),
)?;
let init_mint_ix = initialize_mint_base(
&spl_token_2022::id(),
&mint.pubkey(),
&payer.pubkey(), // mint authority
None, // freeze authority
decimals,
)?;
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?

목차

페이지 편집