PausableExtension nasıl etkinleştirilir
PausableExtension,
belirlenmiş bir duraklama yetkisinin bir mint üzerindeki tüm token
faaliyetlerini durdurmasına olanak tanır. Duraklama yetkisi, mint'i istediği
zaman duraklatabilir veya duraklatmayı kaldırabilir.
Duraklatıldığında, Token-2022 programı o token için tüm transferleri, basımları ve yakmaları reddeder. Duraklama kaldırıldığında, normal işlemler devam eder.
Bu, hem blockchain token sistemlerinde hem de geleneksel finansta yaygın bir kalıptır; burada uyumluluk, olay müdahalesi veya idari kontrol için faaliyeti dondurma yeteneği gereklidir.
Typescript
import {airdropFactory,appendTransactionMessageInstructions,assertIsTransactionWithBlockhashLifetime,createSolanaRpc,createSolanaRpcSubscriptions,createTransactionMessage,generateKeyPairSigner,getSignatureFromTransaction,lamports,pipe,sendAndConfirmTransactionFactory,setTransactionMessageFeePayerSigner,setTransactionMessageLifetimeUsingBlockhash,signTransactionMessageWithSigners} from "@solana/kit";import { getCreateAccountInstruction } from "@solana-program/system";import {extension,fetchMint,findAssociatedTokenPda,getCreateAssociatedTokenInstructionAsync,getInitializeMintInstruction,getInitializePausableConfigInstruction,getMintSize,getMintToInstruction,getPauseInstruction,getResumeInstruction,getTransferCheckedInstruction,TOKEN_2022_PROGRAM_ADDRESS} from "@solana-program/token-2022";// Create Connection, local validator in this exampleconst rpc = createSolanaRpc("http://localhost:8899");const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");const sendAndConfirm = sendAndConfirmTransactionFactory({rpc,rpcSubscriptions});// Generate the authority (fee payer, mint authority, freeze authority, pause authority)const authority = await generateKeyPairSigner();// Fund authority/fee payerawait airdropFactory({ rpc, rpcSubscriptions })({recipientAddress: authority.address,lamports: lamports(5_000_000_000n), // 5 SOLcommitment: "confirmed"});// ---------- Create mint with Pausable extension ----------const mint = await generateKeyPairSigner();// Define the pausable extension for size calculationconst pausableExtension = extension("PausableConfig", {authority: authority.address,paused: false});// Calculate space for mint account with the Pausable extensionconst space = BigInt(getMintSize([pausableExtension]));// Get minimum balance for rent exemptionconst rent = await rpc.getMinimumBalanceForRentExemption(space).send();// Get latest blockhashconst { value: latestBlockhash } = await rpc.getLatestBlockhash().send();// 1) Create the mint accountconst createMintAccountInstruction = getCreateAccountInstruction({payer: authority,newAccount: mint,lamports: rent,space,programAddress: TOKEN_2022_PROGRAM_ADDRESS});// 2) Initialize the pausable extension (must come BEFORE initializeMint)const initializePausableInstruction = getInitializePausableConfigInstruction({mint: mint.address,authority: authority.address});// 3) Initialize the mintconst initializeMintInstruction = getInitializeMintInstruction({mint: mint.address,decimals: 9,mintAuthority: authority.address,freezeAuthority: authority.address});// 4) Create associated token account for authorityconst [authorityAta] = await findAssociatedTokenPda({mint: mint.address,owner: authority.address,tokenProgram: TOKEN_2022_PROGRAM_ADDRESS});const createAtaInstruction = await getCreateAssociatedTokenInstructionAsync({payer: authority,mint: mint.address,owner: authority.address});// 5) Mint 100 tokens (100 * 10^9)const mintToInstruction = getMintToInstruction({mint: mint.address,token: authorityAta,mintAuthority: authority,amount: 100_000_000_000n});// 6) Create recipient and their ATAconst recipient = await generateKeyPairSigner();const [recipientAta] = await findAssociatedTokenPda({mint: mint.address,owner: recipient.address,tokenProgram: TOKEN_2022_PROGRAM_ADDRESS});const createRecipientAtaInstruction =await getCreateAssociatedTokenInstructionAsync({payer: authority,mint: mint.address,owner: recipient.address});// Send transaction to create mint with pausable extension, ATAs, and mint tokensconst createMintTx = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(authority, tx),(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),(tx) =>appendTransactionMessageInstructions([createMintAccountInstruction,initializePausableInstruction,initializeMintInstruction,createAtaInstruction,mintToInstruction,createRecipientAtaInstruction],tx));const signedCreateMintTx =await signTransactionMessageWithSigners(createMintTx);assertIsTransactionWithBlockhashLifetime(signedCreateMintTx);await sendAndConfirm(signedCreateMintTx, {commitment: "confirmed",skipPreflight: true});console.log("Mint created with Pausable extension:", mint.address);// Read back the pausable config from the mintlet mintAccount = await fetchMint(rpc, mint.address);console.log("Pausable config:", mintAccount.data.extensions);// ---------- Pause the mint ----------const pauseInstruction = getPauseInstruction({mint: mint.address,authority: authority});const { value: latestBlockhash2 } = await rpc.getLatestBlockhash().send();const pauseTx = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(authority, tx),(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash2, tx),(tx) => appendTransactionMessageInstructions([pauseInstruction], tx));const signedPauseTx = await signTransactionMessageWithSigners(pauseTx);assertIsTransactionWithBlockhashLifetime(signedPauseTx);await sendAndConfirm(signedPauseTx, {commitment: "confirmed"});console.log("\nMint is now PAUSED");// Verify paused statemintAccount = await fetchMint(rpc, mint.address);console.log("Pausable config:", mintAccount.data.extensions);// Try a transfer while paused (should fail)const transferInstruction = getTransferCheckedInstruction({source: authorityAta,mint: mint.address,destination: recipientAta,authority: authority,amount: 1_000_000_000n, // 1 tokendecimals: 9});const { value: latestBlockhash3 } = await rpc.getLatestBlockhash().send();const transferWhilePausedTx = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(authority, tx),(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash3, tx),(tx) => appendTransactionMessageInstructions([transferInstruction], tx));const signedTransferWhilePausedTx = await signTransactionMessageWithSigners(transferWhilePausedTx);console.log("\nTransfer Expected to Fail with Error:");try {assertIsTransactionWithBlockhashLifetime(signedTransferWhilePausedTx);await sendAndConfirm(signedTransferWhilePausedTx, {commitment: "confirmed"});} catch (error: any) {console.log(" ", error.message ?? error);}// ---------- Resume (unpause) the mint ----------const resumeInstruction = getResumeInstruction({mint: mint.address,authority: authority});const { value: latestBlockhash4 } = await rpc.getLatestBlockhash().send();const resumeTx = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(authority, tx),(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash4, tx),(tx) => appendTransactionMessageInstructions([resumeInstruction], tx));const signedResumeTx = await signTransactionMessageWithSigners(resumeTx);assertIsTransactionWithBlockhashLifetime(signedResumeTx);await sendAndConfirm(signedResumeTx, {commitment: "confirmed"});console.log("\nMint is now RESUMED");// Verify resumed statemintAccount = await fetchMint(rpc, mint.address);console.log("Pausable config:", mintAccount.data.extensions);// Transfer should now succeed after resumeconst { value: latestBlockhash5 } = await rpc.getLatestBlockhash().send();const transferAfterResumeTx = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(authority, tx),(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash5, tx),(tx) => appendTransactionMessageInstructions([transferInstruction], tx));const signedTransferAfterResumeTx = await signTransactionMessageWithSigners(transferAfterResumeTx);assertIsTransactionWithBlockhashLifetime(signedTransferAfterResumeTx);await sendAndConfirm(signedTransferAfterResumeTx, {commitment: "confirmed"});const transferSig = getSignatureFromTransaction(signedTransferAfterResumeTx);console.log("\nTransfer after resume succeeded!");console.log("Transaction Signature:", transferSig);
Console
Click to execute the code.
Rust
Rust
use anyhow::Result;use solana_client::nonblocking::rpc_client::RpcClient;use solana_commitment_config::CommitmentConfig;use solana_sdk::{signature::{Keypair, Signer},transaction::Transaction,};use solana_system_interface::instruction::create_account;use spl_associated_token_account_interface::{address::get_associated_token_address_with_program_id,instruction::create_associated_token_account,};use spl_token_2022_interface::{extension::{pausable::{instruction as pausable_ix, PausableConfig},BaseStateWithExtensions, ExtensionType, StateWithExtensions,},instruction::{initialize_mint, mint_to, transfer_checked},state::{Account, Mint},ID as TOKEN_2022_PROGRAM_ID,};#[tokio::main]async fn main() -> Result<()> {let client = RpcClient::new_with_commitment(String::from("http://localhost:8899"),CommitmentConfig::confirmed(),);let latest_blockhash = client.get_latest_blockhash().await?;let fee_payer = Keypair::new();// Airdrop SOL to fee payerlet airdrop_signature = client.request_airdrop(&fee_payer.pubkey(), 5_000_000_000).await?;loop {let confirmed = client.confirm_transaction(&airdrop_signature).await?;if confirmed {break;}}// ---------- Create mint with Pausable extension ----------let mint = Keypair::new();// Calculate space for mint account with the Pausable extensionlet mint_space = ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::Pausable])?;let mint_rent = client.get_minimum_balance_for_rent_exemption(mint_space).await?;// 1) Create the mint accountlet create_mint_account_ix = create_account(&fee_payer.pubkey(),&mint.pubkey(),mint_rent,mint_space as u64,&TOKEN_2022_PROGRAM_ID,);// 2) Initialize the pausable extension (must come BEFORE initialize_mint)let initialize_pausable_ix = pausable_ix::initialize(&TOKEN_2022_PROGRAM_ID,&mint.pubkey(),&fee_payer.pubkey(), // pause authority)?;// 3) Initialize the mintlet initialize_mint_ix = initialize_mint(&TOKEN_2022_PROGRAM_ID,&mint.pubkey(),&fee_payer.pubkey(), // mint authoritySome(&fee_payer.pubkey()), // freeze authority9, // decimals)?;// 4) Create associated token account for fee_payerlet ata = get_associated_token_address_with_program_id(&fee_payer.pubkey(),&mint.pubkey(),&TOKEN_2022_PROGRAM_ID,);let create_ata_ix = create_associated_token_account(&fee_payer.pubkey(),&fee_payer.pubkey(),&mint.pubkey(),&TOKEN_2022_PROGRAM_ID,);// 5) Mint 100 tokenslet amount = 100_000_000_000; // 100 tokens with 9 decimalslet mint_to_ix = mint_to(&TOKEN_2022_PROGRAM_ID,&mint.pubkey(),&ata,&fee_payer.pubkey(),&[&fee_payer.pubkey()],amount,)?;// 6) Create recipient ATAlet recipient = Keypair::new();let recipient_ata = get_associated_token_address_with_program_id(&recipient.pubkey(),&mint.pubkey(),&TOKEN_2022_PROGRAM_ID,);let create_recipient_ata_ix = create_associated_token_account(&fee_payer.pubkey(),&recipient.pubkey(),&mint.pubkey(),&TOKEN_2022_PROGRAM_ID,);let tx = Transaction::new_signed_with_payer(&[create_mint_account_ix,initialize_pausable_ix,initialize_mint_ix,create_ata_ix,mint_to_ix,create_recipient_ata_ix,],Some(&fee_payer.pubkey()),&[&fee_payer, &mint],latest_blockhash,);client.send_and_confirm_transaction(&tx).await?;println!("Mint created with Pausable extension: {}", mint.pubkey());// Read back the pausable config from the mintlet mint_data = client.get_account(&mint.pubkey()).await?;let mint_state = StateWithExtensions::<Mint>::unpack(&mint_data.data)?;let pausable = mint_state.get_extension::<PausableConfig>()?;println!("Pausable config: {:#?}", pausable);// ---------- Pause the mint ----------let pause_ix = pausable_ix::pause(&TOKEN_2022_PROGRAM_ID,&mint.pubkey(),&fee_payer.pubkey(), // pause authority&[&fee_payer.pubkey()],)?;let latest_blockhash = client.get_latest_blockhash().await?;let tx = Transaction::new_signed_with_payer(&[pause_ix],Some(&fee_payer.pubkey()),&[&fee_payer],latest_blockhash,);client.send_and_confirm_transaction(&tx).await?;println!("\nMint is now PAUSED");// Verify paused statelet mint_data = client.get_account(&mint.pubkey()).await?;let mint_state = StateWithExtensions::<Mint>::unpack(&mint_data.data)?;let pausable = mint_state.get_extension::<PausableConfig>()?;println!("Pausable config: {:#?}", pausable);// Try a transfer while paused (should fail)let transfer_ix = transfer_checked(&TOKEN_2022_PROGRAM_ID,&ata,&mint.pubkey(),&recipient_ata,&fee_payer.pubkey(),&[&fee_payer.pubkey()],1_000_000_000, // 1 token9,)?;let latest_blockhash = client.get_latest_blockhash().await?;let tx = Transaction::new_signed_with_payer(&[transfer_ix.clone()],Some(&fee_payer.pubkey()),&[&fee_payer],latest_blockhash,);println!("\nTransfer Expected to Fail with Error:");let result = client.simulate_transaction(&tx).await?;if result.value.err.is_some() {if let Some(logs) = result.value.logs {for log in logs.iter().filter(|l| l.starts_with("Program log:")) {println!(" {}", log);}}}// ---------- Resume (unpause) the mint ----------let resume_ix = pausable_ix::resume(&TOKEN_2022_PROGRAM_ID,&mint.pubkey(),&fee_payer.pubkey(), // pause authority&[&fee_payer.pubkey()],)?;let latest_blockhash = client.get_latest_blockhash().await?;let tx = Transaction::new_signed_with_payer(&[resume_ix],Some(&fee_payer.pubkey()),&[&fee_payer],latest_blockhash,);client.send_and_confirm_transaction(&tx).await?;println!("\nMint is now RESUMED");// Verify resumed statelet mint_data = client.get_account(&mint.pubkey()).await?;let mint_state = StateWithExtensions::<Mint>::unpack(&mint_data.data)?;let pausable = mint_state.get_extension::<PausableConfig>()?;println!("Pausable config: {:#?}", pausable);// Transfer should now succeedlet latest_blockhash = client.get_latest_blockhash().await?;let tx = Transaction::new_signed_with_payer(&[transfer_ix],Some(&fee_payer.pubkey()),&[&fee_payer],latest_blockhash,);let sig = client.send_and_confirm_transaction(&tx).await?;println!("\nTransfer after resume succeeded!");println!("Transaction Signature: {}", sig);// Verify recipient received the tokenslet recipient_data = client.get_account(&recipient_ata).await?;let recipient_state = StateWithExtensions::<Account>::unpack(&recipient_data.data)?;println!("\nRecipient Token Account: {:#?}", recipient_state.base);Ok(())}
Console
Click to execute the code.
Is this page helpful?