مجموعات الرموز والأعضاء
كيفية تمكين GroupPointerExtension وGroupMemberPointerExtension
يقوم
GroupPointerExtension
بتعيين mint كـ mint مجموعة (مثل NFT مجموعة) من خلال الإشارة إلى حساب يحتوي على
إعدادات المجموعة
مثل سلطة التحديث والحجم الأقصى.
يقوم
GroupMemberPointerExtension
بتعيين mint كـ mint عضو (مثل NFT في مجموعة) من خلال الإشارة إلى حساب يحتوي على
بيانات العضوية
مثل عنوان المجموعة ورقم العضو.
ينفذ Token Extensions Program واجهة Token Group بشكل مباشر، مما يسمح بتخزين بيانات المجموعة والعضو على حساب mint نفسه. عندما تشير امتدادات المؤشر إلى mint نفسه، يمكن استخدام TokenGroup و TokenGroupMember لتخزين جميع بيانات المجموعة والعضوية في حساب mint.
تايبسكريبت
import { getCreateAccountInstruction } from "@solana-program/system";import {extension,getInitializeAccountInstruction,getInitializeMintInstruction,getInitializeGroupPointerInstruction,getMintSize,TOKEN_2022_PROGRAM_ADDRESS,getInitializeTokenGroupInstruction,getInitializeGroupMemberPointerInstruction,getInitializeTokenGroupMemberInstruction} from "@solana-program/token-2022";import {airdropFactory,appendTransactionMessageInstructions,createSolanaRpc,createSolanaRpcSubscriptions,createTransactionMessage,generateKeyPairSigner,getSignatureFromTransaction,lamports,pipe,sendAndConfirmTransactionFactory,setTransactionMessageFeePayerSigner,setTransactionMessageLifetimeUsingBlockhash,signTransactionMessageWithSigners,some} from "@solana/kit";// Create Connection, local validator in this exampleconst rpc = createSolanaRpc("http://localhost:8899");const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");// Generate the authority for the mint (also acts as fee payer)const authority = await generateKeyPairSigner();// Fund authority/fee payerawait airdropFactory({ rpc, rpcSubscriptions })({recipientAddress: authority.address,lamports: lamports(5_000_000_000n), // 5 SOLcommitment: "confirmed"});// ===== GROUP MINT CREATION =====// Generate keypair to use as address of group mintconst groupMint = await generateKeyPairSigner();// Group pointer extension (points to external group account)const groupPointerExtension = extension("GroupPointer", {authority: authority.address,groupAddress: groupMint.address // Points to the group mint itself});// Group extension (stores group data directly on mint)const groupExtension = extension("TokenGroup", {updateAuthority: some(authority.address),mint: groupMint.address,size: 1, // Will be incremented when members are addedmaxSize: 10});// Get mint account size with group pointer extensionconst spaceWithGroupPointerExtensions = BigInt(getMintSize([groupPointerExtension]));// Get mint account size with group pointer and group extensionconst spaceWithGroupAndGroupPointerExtensions = BigInt(getMintSize([groupPointerExtension, groupExtension]));// Get rent exempt balance for group mintconst groupMintRent = await rpc.getMinimumBalanceForRentExemption(spaceWithGroupAndGroupPointerExtensions).send();// Get latest blockhashconst { value: latestBlockhash } = await rpc.getLatestBlockhash().send();// GROUP MINT INSTRUCTIONSconst createGroupMintAccountInstruction = getCreateAccountInstruction({payer: authority,newAccount: groupMint,lamports: groupMintRent,space: spaceWithGroupPointerExtensions,programAddress: TOKEN_2022_PROGRAM_ADDRESS});const initializeGroupPointerInstruction = getInitializeGroupPointerInstruction({mint: groupMint.address,authority: authority.address,groupAddress: groupMint.address});const initializeGroupMintInstruction = getInitializeMintInstruction({mint: groupMint.address,decimals: 0, // NFT-stylemintAuthority: authority.address,freezeAuthority: authority.address});const initializeGroupInstruction = getInitializeTokenGroupInstruction({group: groupMint.address,mint: groupMint.address,mintAuthority: authority,updateAuthority: authority.address,maxSize: 10});// Build group mint transactionconst groupInstructions = [createGroupMintAccountInstruction,initializeGroupPointerInstruction,initializeGroupMintInstruction,initializeGroupInstruction];const groupTransactionMessage = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(authority, tx),(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),(tx) => appendTransactionMessageInstructions(groupInstructions, tx));const signedGroupTransaction = await signTransactionMessageWithSigners(groupTransactionMessage);await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedGroupTransaction,{ commitment: "confirmed", skipPreflight: true });const groupTransactionSignature = getSignatureFromTransaction(signedGroupTransaction);console.log("Group Mint Address:", groupMint.address.toString());console.log("Group Transaction Signature:", groupTransactionSignature);// ===== MEMBER MINT CREATION =====// Generate keypair for member mintconst memberMint = await generateKeyPairSigner();// Member pointer extension (points to external member account)const memberPointerExtension = extension("GroupMemberPointer", {authority: authority.address,memberAddress: memberMint.address // Points to the member mint itself});// Member extension (stores membership data directly on mint)const memberExtension = extension("TokenGroupMember", {mint: memberMint.address,group: groupMint.address, // References the group mint we created abovememberNumber: 1 // First member of the group});// Get mint account size with group pointer extensionconst spaceWithMemberPointerExtension = BigInt(getMintSize([groupPointerExtension]));// Get mint account size with group pointer and group extensionconst spaceWithMemberAndMemberPointerExtensions = BigInt(getMintSize([groupPointerExtension, groupExtension]));// Get rent exempt balance for member mintconst memberMintRent = await rpc.getMinimumBalanceForRentExemption(spaceWithMemberAndMemberPointerExtensions).send();// Get fresh blockhash for member mint transactionconst { value: memberLatestBlockhash } = await rpc.getLatestBlockhash().send();// MEMBER MINT INSTRUCTIONSconst createMemberMintAccountInstruction = getCreateAccountInstruction({payer: authority,newAccount: memberMint,lamports: memberMintRent,space: spaceWithMemberPointerExtension, // Only pointer extension space for account creationprogramAddress: TOKEN_2022_PROGRAM_ADDRESS});const initializeMemberPointerInstruction =getInitializeGroupMemberPointerInstruction({mint: memberMint.address,authority: authority.address,memberAddress: memberMint.address});const initializeMemberMintInstruction = getInitializeMintInstruction({mint: memberMint.address,decimals: 0, // NFT-stylemintAuthority: authority.address,freezeAuthority: authority.address});// Initialize member extension (added post-mint initialization)const initializeMemberInstruction = getInitializeTokenGroupMemberInstruction({member: memberMint.address,memberMint: memberMint.address,memberMintAuthority: authority,group: groupMint.address, // References the group mintgroupUpdateAuthority: authority});// Build member mint transactionconst memberInstructions = [createMemberMintAccountInstruction,initializeMemberPointerInstruction,initializeMemberMintInstruction,initializeMemberInstruction];const memberTransactionMessage = pipe(createTransactionMessage({ version: 0 }),(tx) => setTransactionMessageFeePayerSigner(authority, tx),(tx) =>setTransactionMessageLifetimeUsingBlockhash(memberLatestBlockhash, tx),(tx) => appendTransactionMessageInstructions(memberInstructions, tx));const signedMemberTransaction = await signTransactionMessageWithSigners(memberTransactionMessage);await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedMemberTransaction,{ commitment: "confirmed", skipPreflight: true });const memberTransactionSignature = getSignatureFromTransaction(signedMemberTransaction);console.log("Member Mint Address:", memberMint.address.toString());console.log("Member Transaction Signature:", memberTransactionSignature);console.log("\n===== SUMMARY =====");console.log("Group Mint:", groupMint.address.toString());console.log("Member Mint:", memberMint.address.toString());console.log("Member belongs to Group:", groupMint.address.toString());
Console
Click to execute the code.
راست
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_token_2022_interface::{extension::{group_member_pointer::{instruction::initialize as initialize_group_member_pointer, GroupMemberPointer,},group_pointer::{instruction::initialize as initialize_group_pointer, GroupPointer},BaseStateWithExtensions, ExtensionType, StateWithExtensions,},instruction::initialize_mint,state::Mint,ID as TOKEN_2022_PROGRAM_ID,};use spl_token_group_interface::{instruction::{initialize_group, initialize_member},state::{TokenGroup, TokenGroupMember},};#[tokio::main]async fn main() -> Result<()> {// Create connection to local validatorlet client = RpcClient::new_with_commitment(String::from("http://localhost:8899"),CommitmentConfig::confirmed(),);let latest_blockhash = client.get_latest_blockhash().await?;// Generate the authority for the mint (also acts as fee payer)let authority = Keypair::new();// Airdrop 5 SOL to authority/fee payerlet airdrop_signature = client.request_airdrop(&authority.pubkey(), 5_000_000_000).await?;loop {let confirmed = client.confirm_transaction(&airdrop_signature).await?;if confirmed {break;}}// Create group mint// Generate keypair to use as address of group mintlet group_mint = Keypair::new();// Calculate space for mint with group pointer extension only (for account creation)let group_mint_space =ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::GroupPointer])?;// Calculate space for mint with group pointer and group extension (for rent calculation)let group_mint_space_with_data = ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::GroupPointer,ExtensionType::TokenGroup,])?;// Get rent exempt balance for full space (including data extension)let group_mint_rent = client.get_minimum_balance_for_rent_exemption(group_mint_space_with_data).await?;let create_group_mint_account_instruction = create_account(&authority.pubkey(), // payer&group_mint.pubkey(), // new account (mint)group_mint_rent, // lamportsgroup_mint_space as u64, // space (pointer only for account creation)&TOKEN_2022_PROGRAM_ID, // program id);let initialize_group_pointer_instruction = initialize_group_pointer(&TOKEN_2022_PROGRAM_ID,&group_mint.pubkey(), // mintSome(authority.pubkey()), // authoritySome(group_mint.pubkey()), // group address (points to itself))?;let initialize_group_mint_instruction = initialize_mint(&TOKEN_2022_PROGRAM_ID, // program id&group_mint.pubkey(), // mint&authority.pubkey(), // mint authoritySome(&authority.pubkey()), // freeze authority0, // decimals (NFT-style))?;// Initialize group extension (added post-mint initialization)let initialize_group_instruction = initialize_group(&TOKEN_2022_PROGRAM_ID, // program id&group_mint.pubkey(), // group&group_mint.pubkey(), // mint&authority.pubkey(), // mint authoritySome(authority.pubkey()), // update authority10, // max size);// Build group mint transactionlet group_transaction = Transaction::new_signed_with_payer(&[create_group_mint_account_instruction,initialize_group_pointer_instruction,initialize_group_mint_instruction,initialize_group_instruction,],Some(&authority.pubkey()),&[&authority, &group_mint],latest_blockhash,);client.send_and_confirm_transaction(&group_transaction).await?;// Generate keypair for member mintlet member_mint = Keypair::new();// Calculate space for mint with member pointer extension only (for account creation)let member_mint_space =ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::GroupMemberPointer])?;// Calculate space for mint with member pointer and member extension (for rent calculation)let member_mint_space_with_data = ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::GroupMemberPointer,ExtensionType::TokenGroupMember,])?;// Get rent exempt balance for full space (including data extension)let member_mint_rent = client.get_minimum_balance_for_rent_exemption(member_mint_space_with_data).await?;let create_member_mint_account_instruction = create_account(&authority.pubkey(), // payer&member_mint.pubkey(), // new account (mint)member_mint_rent, // lamportsmember_mint_space as u64, // space (pointer only for account creation)&TOKEN_2022_PROGRAM_ID, // program id);let initialize_member_pointer_instruction = initialize_group_member_pointer(&TOKEN_2022_PROGRAM_ID,&member_mint.pubkey(), // mintSome(authority.pubkey()), // authoritySome(member_mint.pubkey()), // member address (points to itself))?;let initialize_member_mint_instruction = initialize_mint(&TOKEN_2022_PROGRAM_ID, // program id&member_mint.pubkey(), // mint&authority.pubkey(), // mint authoritySome(&authority.pubkey()), // freeze authority0, // decimals (NFT-style))?;// Initialize member extension (added post-mint initialization)let initialize_member_instruction = initialize_member(&TOKEN_2022_PROGRAM_ID, // program id&member_mint.pubkey(), // member&member_mint.pubkey(), // member mint&authority.pubkey(), // member mint authority&group_mint.pubkey(), // group (references the group mint)&authority.pubkey(), // group update authority);// Build member mint transactionlet member_transaction = Transaction::new_signed_with_payer(&[create_member_mint_account_instruction,initialize_member_pointer_instruction,initialize_member_mint_instruction,initialize_member_instruction,],Some(&authority.pubkey()),&[&authority, &member_mint],latest_blockhash,);// Send and confirm member transactionclient.send_and_confirm_transaction(&member_transaction).await?;println!("Group Mint: {}", group_mint.pubkey());// Fetch and deserialize group mintlet group_mint_account = client.get_account(&group_mint.pubkey()).await?;let group_mint_state = StateWithExtensions::<Mint>::unpack(&group_mint_account.data)?;let group_extension_types = group_mint_state.get_extension_types()?;println!("Extensions enabled: {:?}", group_extension_types);let group_pointer = group_mint_state.get_extension::<GroupPointer>()?;println!("\n{:#?}", group_pointer);let token_group = group_mint_state.get_extension::<TokenGroup>()?;println!("\n{:#?}", token_group);println!("\nMember Mint: {}", member_mint.pubkey());// Fetch and deserialize member mintlet member_mint_account = client.get_account(&member_mint.pubkey()).await?;let member_mint_state = StateWithExtensions::<Mint>::unpack(&member_mint_account.data)?;let member_extension_types = member_mint_state.get_extension_types()?;println!("Extensions enabled: {:?}", member_extension_types);let member_pointer = member_mint_state.get_extension::<GroupMemberPointer>()?;println!("\n{:#?}", member_pointer);let token_group_member = member_mint_state.get_extension::<TokenGroupMember>()?;println!("\n{:#?}", token_group_member);Ok(())}
Console
Click to execute the code.
Is this page helpful?