Cosa Sono le Estensioni Group e Group Member?
Un gruppo è un mint che rappresenta una collezione. Un membro del gruppo è un mint che appartiene a quella collezione.
Utilizza queste estensioni quando un mint deve rappresentare la collezione e altri mint devono rappresentare gli elementi che vi appartengono.
Il Token Extensions Program può memorizzare i dati del gruppo di token direttamente su un mint con quattro estensioni correlate:
GroupPointerpunta un mint all'account che memorizza i dati del gruppo.TokenGroupmemorizza i dati del gruppo stesso, inclusa l'autorità di aggiornamento, la dimensione corrente e la dimensione massima.GroupMemberPointerpunta un mint all'account che memorizza i dati del membro.TokenGroupMembermemorizza l'indirizzo del gruppo del membro e il numero del membro.
GroupPointer e GroupMemberPointer possono fare riferimento a
qualsiasi account di proprietà di un programma che implementa
l'interfaccia Token group.
Il Token Extensions Program implementa anche quell'interfaccia direttamente
tramite le estensioni mint TokenGroup e TokenGroupMember.
Come Creare Gruppi e Membri Memorizzati sul Mint Account
Per creare gruppi e membri memorizzati sul mint account:
- Crea un mint account di gruppo e inizializza
GroupPointer. - Inizializza il mint di gruppo con
InitializeMint. - Inizializza
TokenGroupsu quello stesso mint. - Crea un mint account di membro e inizializza
GroupMemberPointer. - Inizializza il mint di membro con
InitializeMint. - Inizializza
TokenGroupMembersu quello stesso mint in modo che faccia riferimento al mint di gruppo.
Calcolare la dimensione e il rent del mint di gruppo
Calcola la dimensione e il rent necessari per il mint di gruppo.
Creare e inizializzare il mint di gruppo
Crea l'account del mint di gruppo, inizializza GroupPointer, inizializza
il mint e inizializza TokenGroup in un'unica transazione.
Calcolare la dimensione e il rent del mint membro
Calcola la dimensione e il rent necessari per il mint membro.
Creare e inizializzare il mint membro
Crea l'account del mint membro, inizializza GroupMemberPointer,
inizializza il mint e inizializza TokenGroupMember in un'unica
transazione.
Puntatori e ordine delle istruzioni
GroupPointer e GroupMemberPointer memorizzano l'indirizzo dell'account
in cui risiedono i dati del gruppo o del membro. TokenGroup e
TokenGroupMember memorizzano i dati effettivi del gruppo o del membro.
GroupPointerInstruction::Initialize e
GroupMemberPointerInstruction::Initialize devono precedere
InitializeMint. TokenGroupInstruction::InitializeGroup e
TokenGroupInstruction::InitializeMember devono seguire
InitializeMint. Per ogni mint, CreateAccount, l'istruzione di
inizializzazione del puntatore e InitializeMint devono essere inclusi
nella stessa transazione.
Riferimento sorgente
GroupPointer e GroupMemberPointer sono istruzioni di puntatore nel
Token Extensions Program. TokenGroup e TokenGroupMember seguono
l'interfaccia Token group, implementata dal Token Extensions Program.
Group Pointer e Group Member Pointer
| Elemento | Descrizione | Sorgente |
|---|---|---|
GroupPointer | Estensione del mint che memorizza l'autorità e l'indirizzo per l'account che contiene i dati di un gruppo. | Sorgente |
GroupMemberPointer | Estensione del mint che memorizza l'autorità e l'indirizzo per l'account che contiene i dati di un membro. | Sorgente |
GroupPointerInstruction::Initialize | Inizializza l'estensione group pointer prima di InitializeMint. | Sorgente |
GroupPointerInstruction::Update | Aggiorna l'indirizzo del gruppo memorizzato dall'estensione GroupPointer del mint. | Sorgente |
GroupMemberPointerInstruction::Initialize | Inizializza l'estensione group member pointer prima di InitializeMint. | Sorgente |
GroupMemberPointerInstruction::Update | Aggiorna l'indirizzo del membro memorizzato dall'estensione GroupMemberPointer del mint. | Sorgente |
process_initialize (GroupPointer) | Scrive l'autorità iniziale di GroupPointer e l'indirizzo del gruppo sul mint. | Sorgente |
process_update (GroupPointer) | Valida l'autorità del group pointer, quindi riscrive l'indirizzo del gruppo memorizzato nel mint. | Sorgente |
process_initialize (GroupMemberPointer) | Scrive l'autorità iniziale di GroupMemberPointer e l'indirizzo del membro sul mint. | Sorgente |
process_update (GroupMemberPointer) | Valida l'autorità del group member pointer, quindi riscrive l'indirizzo del membro memorizzato nel mint. | Sorgente |
Token Group e Token Group Member
| Elemento | Descrizione | Fonte |
|---|---|---|
TokenGroup | Stato dell'interfaccia del gruppo di token memorizzato sul mint, inclusi l'autorità di aggiornamento, la dimensione corrente e la dimensione massima. | Fonte |
TokenGroupMember | Stato dell'interfaccia del membro del gruppo di token memorizzato sul mint, inclusi il mint del membro, l'indirizzo del gruppo e il numero del membro. | Fonte |
TokenGroupInstruction::InitializeGroup | Istruzione dell'interfaccia del gruppo di token supportata dal Token Extensions Program per inizializzare un nuovo gruppo per un mint già inizializzato. | Fonte |
TokenGroupInstruction::UpdateGroupMaxSize | Istruzione dell'interfaccia del gruppo di token supportata dal Token Extensions Program per aggiornare il numero massimo di membri consentiti in un gruppo. | Fonte |
TokenGroupInstruction::UpdateGroupAuthority | Istruzione dell'interfaccia del gruppo di token supportata dal Token Extensions Program per ruotare o eliminare l'autorità di aggiornamento del gruppo. | Fonte |
TokenGroupInstruction::InitializeMember | Istruzione dell'interfaccia del gruppo di token supportata dal Token Extensions Program per inizializzare un nuovo membro per un gruppo già inizializzato. | Fonte |
process_initialize_group | Convalida il mint, verifica che GroupPointer sia presente e alloca lo stato TokenGroup sul mint del gruppo. | Fonte |
process_update_group_max_size | Convalida l'autorità di aggiornamento corrente, quindi aggiorna la dimensione massima del gruppo. | Fonte |
process_update_group_authority | Convalida l'autorità di aggiornamento corrente, quindi ruota o elimina l'autorità di aggiornamento del gruppo. | Fonte |
process_initialize_member | Convalida il mint del membro e l'autorità del gruppo, incrementa la dimensione del gruppo e alloca lo stato TokenGroupMember sul mint. | Fonte |
Typescript
L'esempio Kit qui sotto utilizza direttamente le istruzioni generate. Gli
esempi legacy che utilizzano @solana/web3.js, @solana/spl-token e gli helper
di gruppo token sono inclusi come riferimento.
Kit
import {lamports,createClient,generateKeyPairSigner,unwrapOption} from "@solana/kit";import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";import { getCreateAccountInstruction } from "@solana-program/system";import {extension,fetchMint,getInitializeGroupMemberPointerInstruction,getInitializeGroupPointerInstruction,getInitializeMintInstruction,getInitializeTokenGroupInstruction,getInitializeTokenGroupMemberInstruction,getMintSize,isExtension,TOKEN_2022_PROGRAM_ADDRESS} from "@solana-program/token-2022";const client = await createClient().use(generatedPayer()).use(solanaRpc({rpcUrl: "http://localhost:8899",rpcSubscriptionsUrl: "ws://localhost:8900"})).use(rpcAirdrop()).use(airdropPayer(lamports(1_000_000_000n)));const groupMint = await generateKeyPairSigner();const memberMint = await generateKeyPairSigner();const groupPointerExtension = extension("GroupPointer", {authority: client.payer.address,groupAddress: groupMint.address});const groupExtension = extension("TokenGroup", {updateAuthority: client.payer.address,mint: groupMint.address,size: 0n,maxSize: 10n});const groupMintSpace = BigInt(getMintSize([groupPointerExtension, groupExtension]));const groupMintCreateSpace = BigInt(getMintSize([groupPointerExtension]));const groupMintRent = await client.rpc.getMinimumBalanceForRentExemption(groupMintSpace).send();await client.sendTransaction([getCreateAccountInstruction({payer: client.payer, // Account funding the new mint account.newAccount: groupMint, // New group mint account to create.lamports: groupMintRent, // Lamports funding the mint account rent.space: groupMintCreateSpace, // Account size in bytes for the mint plus GroupPointer.programAddress: TOKEN_2022_PROGRAM_ADDRESS // Program that owns the mint account.}),getInitializeGroupPointerInstruction({mint: groupMint.address, // Mint account that stores the GroupPointer extension.authority: client.payer.address, // Authority allowed to update the group pointer later.groupAddress: groupMint.address // Account address that stores the group data.}),getInitializeMintInstruction({mint: groupMint.address, // Mint account to initialize.decimals: 0, // Number of decimals for the token.mintAuthority: client.payer.address, // Authority allowed to mint new tokens.freezeAuthority: client.payer.address // Authority allowed to freeze token accounts.}),getInitializeTokenGroupInstruction({group: groupMint.address, // Mint account that stores the group data.mint: groupMint.address, // Mint that the group data describes.mintAuthority: client.payer, // Signer authorizing group initialization for the mint.updateAuthority: client.payer.address, // Authority allowed to update the group later.maxSize: 10n // Maximum number of members allowed in the group.})]);const memberPointerExtension = extension("GroupMemberPointer", {authority: client.payer.address,memberAddress: memberMint.address});const memberExtension = extension("TokenGroupMember", {mint: memberMint.address,group: groupMint.address,memberNumber: 1n});const memberMintSpace = BigInt(getMintSize([memberPointerExtension, memberExtension]));const memberMintCreateSpace = BigInt(getMintSize([memberPointerExtension]));const memberMintRent = await client.rpc.getMinimumBalanceForRentExemption(memberMintSpace).send();await client.sendTransaction([getCreateAccountInstruction({payer: client.payer, // Account funding the new mint account.newAccount: memberMint, // New member mint account to create.lamports: memberMintRent, // Lamports funding the mint account rent.space: memberMintCreateSpace, // Account size in bytes for the mint plus GroupMemberPointer.programAddress: TOKEN_2022_PROGRAM_ADDRESS // Program that owns the mint account.}),getInitializeGroupMemberPointerInstruction({mint: memberMint.address, // Mint account that stores the GroupMemberPointer extension.authority: client.payer.address, // Authority allowed to update the member pointer later.memberAddress: memberMint.address // Account address that stores the member data.}),getInitializeMintInstruction({mint: memberMint.address, // Mint account to initialize.decimals: 0, // Number of decimals for the token.mintAuthority: client.payer.address, // Authority allowed to mint new tokens.freezeAuthority: client.payer.address // Authority allowed to freeze token accounts.}),getInitializeTokenGroupMemberInstruction({member: memberMint.address, // Mint account that stores the member data.memberMint: memberMint.address, // Mint that the member data describes.memberMintAuthority: client.payer, // Signer authorizing member initialization for the mint.group: groupMint.address, // Group mint that this member belongs to.groupUpdateAuthority: client.payer // Signer matching the group's update authority.})]);const groupMintAccount = await fetchMint(client.rpc, groupMint.address);const memberMintAccount = await fetchMint(client.rpc, memberMint.address);const groupExtensions = unwrapOption(groupMintAccount.data.extensions) ?? [];const memberExtensions = unwrapOption(memberMintAccount.data.extensions) ?? [];console.log(JSON.stringify({groupMint: groupMint.address,groupPointer: groupExtensions.find((item) =>isExtension("GroupPointer", item)),group: groupExtensions.find((item) => isExtension("TokenGroup", item)),memberMint: memberMint.address,memberPointer: memberExtensions.find((item) =>isExtension("GroupMemberPointer", item)),member: memberExtensions.find((item) =>isExtension("TokenGroupMember", item))},(_, value) => (typeof value === "bigint" ? value.toString() : value),2));
Web3.js
import {Connection,Keypair,Transaction,SystemProgram,LAMPORTS_PER_SOL,sendAndConfirmTransaction} from "@solana/web3.js";import {TOKEN_2022_PROGRAM_ID,ExtensionType,getMintLen,getMint,createInitializeMintInstruction,createInitializeGroupPointerInstruction,createInitializeGroupInstruction,createInitializeGroupMemberPointerInstruction,createInitializeMemberInstruction,getGroupPointerState,getGroupMemberPointerState,getTokenGroupState,getTokenGroupMemberState} from "@solana/spl-token";const connection = new Connection("http://localhost:8899", "confirmed");const authority = Keypair.generate();const airdropSignature = await connection.requestAirdrop(authority.publicKey,5 * LAMPORTS_PER_SOL);await connection.confirmTransaction(airdropSignature, "confirmed");const groupMint = Keypair.generate();const groupPointerExtensions = [ExtensionType.GroupPointer];const spaceWithGroupPointerExtensions = getMintLen(groupPointerExtensions);const groupAndGroupPointerExtensions = [ExtensionType.GroupPointer,ExtensionType.TokenGroup];const spaceWithGroupAndGroupPointerExtensions = getMintLen(groupAndGroupPointerExtensions);const groupMintRent = await connection.getMinimumBalanceForRentExemption(spaceWithGroupAndGroupPointerExtensions);const { blockhash: latestBlockhash } = await connection.getLatestBlockhash();const createGroupMintAccountInstruction = SystemProgram.createAccount({fromPubkey: authority.publicKey, // Account funding the new mint account.newAccountPubkey: groupMint.publicKey, // New group mint account to create.lamports: groupMintRent, // Lamports funding the mint account rent.space: spaceWithGroupPointerExtensions, // Account size in bytes for the mint plus GroupPointer.programId: TOKEN_2022_PROGRAM_ID // Program that owns the mint account.});const initializeGroupPointerInstruction =createInitializeGroupPointerInstruction(groupMint.publicKey, // Mint account that stores the GroupPointer extension.authority.publicKey, // Authority allowed to update the group pointer later.groupMint.publicKey, // Account address that stores the group data.TOKEN_2022_PROGRAM_ID // Program that owns the mint account.);const initializeGroupMintInstruction = createInitializeMintInstruction(groupMint.publicKey, // Mint account to initialize.0, // Number of decimals for the token.authority.publicKey, // Authority allowed to mint new tokens.authority.publicKey, // Authority allowed to freeze token accounts.TOKEN_2022_PROGRAM_ID // Program that owns the mint account.);const initializeGroupInstruction = createInitializeGroupInstruction({programId: TOKEN_2022_PROGRAM_ID, // Token program that owns the mint.group: groupMint.publicKey, // Mint account that stores the group data.mint: groupMint.publicKey, // Mint that the group data describes.mintAuthority: authority.publicKey, // Signer authorizing group initialization for the mint.updateAuthority: authority.publicKey, // Authority allowed to update the group later.maxSize: 10n // Maximum number of members allowed in the group.});const groupTransaction = new Transaction({feePayer: authority.publicKey,recentBlockhash: latestBlockhash}).add(createGroupMintAccountInstruction,initializeGroupPointerInstruction,initializeGroupMintInstruction,initializeGroupInstruction);await sendAndConfirmTransaction(connection,groupTransaction,[authority, groupMint],{commitment: "confirmed",skipPreflight: true});const memberMint = Keypair.generate();const memberPointerExtensions = [ExtensionType.GroupMemberPointer];const spaceWithMemberPointerExtension = getMintLen(memberPointerExtensions);const memberAndMemberPointerExtensions = [ExtensionType.GroupMemberPointer,ExtensionType.TokenGroupMember];const spaceWithMemberAndMemberPointerExtensions = getMintLen(memberAndMemberPointerExtensions);const memberMintRent = await connection.getMinimumBalanceForRentExemption(spaceWithMemberAndMemberPointerExtensions);const { blockhash: memberLatestBlockhash } =await connection.getLatestBlockhash();const createMemberMintAccountInstruction = SystemProgram.createAccount({fromPubkey: authority.publicKey, // Account funding the new mint account.newAccountPubkey: memberMint.publicKey, // New member mint account to create.lamports: memberMintRent, // Lamports funding the mint account rent.space: spaceWithMemberPointerExtension, // Account size in bytes for the mint plus GroupMemberPointer.programId: TOKEN_2022_PROGRAM_ID // Program that owns the mint account.});const initializeMemberPointerInstruction =createInitializeGroupMemberPointerInstruction(memberMint.publicKey, // Mint account that stores the GroupMemberPointer extension.authority.publicKey, // Authority allowed to update the member pointer later.memberMint.publicKey, // Account address that stores the member data.TOKEN_2022_PROGRAM_ID // Program that owns the mint account.);const initializeMemberMintInstruction = createInitializeMintInstruction(memberMint.publicKey, // Mint account to initialize.0, // Number of decimals for the token.authority.publicKey, // Authority allowed to mint new tokens.authority.publicKey, // Authority allowed to freeze token accounts.TOKEN_2022_PROGRAM_ID // Program that owns the mint account.);const initializeMemberInstruction = createInitializeMemberInstruction({programId: TOKEN_2022_PROGRAM_ID, // Token program that owns the mint.member: memberMint.publicKey, // Mint account that stores the member data.memberMint: memberMint.publicKey, // Mint that the member data describes.memberMintAuthority: authority.publicKey, // Signer authorizing member initialization for the mint.group: groupMint.publicKey, // Group mint that this member belongs to.groupUpdateAuthority: authority.publicKey // Signer matching the group's update authority.});const memberTransaction = new Transaction({feePayer: authority.publicKey,recentBlockhash: memberLatestBlockhash}).add(createMemberMintAccountInstruction,initializeMemberPointerInstruction,initializeMemberMintInstruction,initializeMemberInstruction);await sendAndConfirmTransaction(connection,memberTransaction,[authority, memberMint],{commitment: "confirmed",skipPreflight: true});const groupMintAccount = await getMint(connection,groupMint.publicKey,"confirmed",TOKEN_2022_PROGRAM_ID);const memberMintAccount = await getMint(connection,memberMint.publicKey,"confirmed",TOKEN_2022_PROGRAM_ID);console.log(JSON.stringify({groupMint: groupMint.publicKey,groupPointer: getGroupPointerState(groupMintAccount),group: getTokenGroupState(groupMintAccount),memberMint: memberMint.publicKey,memberPointer: getGroupMemberPointerState(memberMintAccount),member: getTokenGroupMemberState(memberMintAccount)},(_, value) => (typeof value === "bigint" ? value.toString() : value),2));
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<()> {let client = RpcClient::new_with_commitment(String::from("http://localhost:8899"),CommitmentConfig::confirmed(),);let authority = Keypair::new();let airdrop_signature = client.request_airdrop(&authority.pubkey(), 5_000_000_000).await?;loop {let confirmed = client.confirm_transaction(&airdrop_signature).await?;if confirmed {break;}}let group_mint = Keypair::new();let group_mint_space =ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::GroupPointer])?;let group_mint_space_with_data = ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::GroupPointer,ExtensionType::TokenGroup,])?;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(), // Account funding the new mint account.&group_mint.pubkey(), // New group mint account to create.group_mint_rent, // Lamports funding the mint account rent.group_mint_space as u64, // Account size in bytes for the mint plus GroupPointer.&TOKEN_2022_PROGRAM_ID, // Program that owns the mint account.);let initialize_group_pointer_instruction = initialize_group_pointer(&TOKEN_2022_PROGRAM_ID,&group_mint.pubkey(), // Mint account that stores the GroupPointer extension.Some(authority.pubkey()), // Authority allowed to update the group pointer later.Some(group_mint.pubkey()), // Account address that stores the group data.)?;let initialize_group_mint_instruction = initialize_mint(&TOKEN_2022_PROGRAM_ID, // Program that owns the mint account.&group_mint.pubkey(), // Mint account to initialize.&authority.pubkey(), // Authority allowed to mint new tokens.Some(&authority.pubkey()), // Authority allowed to freeze token accounts.0, // Number of decimals for the token.)?;let initialize_group_instruction = initialize_group(&TOKEN_2022_PROGRAM_ID, // Program that owns the mint account.&group_mint.pubkey(), // Mint account that stores the group data.&group_mint.pubkey(), // Mint that the group data describes.&authority.pubkey(), // Signer authorizing group initialization for the mint.Some(authority.pubkey()), // Authority allowed to update the group later.10, // Maximum number of members allowed in the group.);let 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],client.get_latest_blockhash().await?,);client.send_and_confirm_transaction(&group_transaction).await?;let member_mint = Keypair::new();let member_mint_space =ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::GroupMemberPointer])?;let member_mint_space_with_data = ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::GroupMemberPointer,ExtensionType::TokenGroupMember,])?;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(), // Account funding the new mint account.&member_mint.pubkey(), // New member mint account to create.member_mint_rent, // Lamports funding the mint account rent.member_mint_space as u64, // Account size in bytes for the mint plus GroupMemberPointer.&TOKEN_2022_PROGRAM_ID, // Program that owns the mint account.);let initialize_member_pointer_instruction = initialize_group_member_pointer(&TOKEN_2022_PROGRAM_ID,&member_mint.pubkey(), // Mint account that stores the GroupMemberPointer extension.Some(authority.pubkey()), // Authority allowed to update the member pointer later.Some(member_mint.pubkey()), // Account address that stores the member data.)?;let initialize_member_mint_instruction = initialize_mint(&TOKEN_2022_PROGRAM_ID, // Program that owns the mint account.&member_mint.pubkey(), // Mint account to initialize.&authority.pubkey(), // Authority allowed to mint new tokens.Some(&authority.pubkey()), // Authority allowed to freeze token accounts.0, // Number of decimals for the token.)?;let initialize_member_instruction = initialize_member(&TOKEN_2022_PROGRAM_ID, // Program that owns the mint account.&member_mint.pubkey(), // Mint account that stores the member data.&member_mint.pubkey(), // Mint that the member data describes.&authority.pubkey(), // Signer authorizing member initialization for the mint.&group_mint.pubkey(), // Group mint that this member belongs to.&authority.pubkey(), // Signer matching the group's update authority.);let 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],client.get_latest_blockhash().await?,);client.send_and_confirm_transaction(&member_transaction).await?;let group_mint_account = client.get_account(&group_mint.pubkey()).await?;let group_mint_state = StateWithExtensions::<Mint>::unpack(&group_mint_account.data)?;let group_pointer = group_mint_state.get_extension::<GroupPointer>()?;let token_group = group_mint_state.get_extension::<TokenGroup>()?;let member_mint_account = client.get_account(&member_mint.pubkey()).await?;let member_mint_state = StateWithExtensions::<Mint>::unpack(&member_mint_account.data)?;let member_pointer = member_mint_state.get_extension::<GroupMemberPointer>()?;let token_group_member = member_mint_state.get_extension::<TokenGroupMember>()?;println!("\nGroup Mint: {}", group_mint.pubkey());println!("\nGroup Pointer: {:#?}", group_pointer);println!("\nToken Group: {:#?}", token_group);println!("\nMember Mint: {}", member_mint.pubkey());println!("\nGroup Member Pointer: {:#?}", member_pointer);println!("\nToken Group Member: {:#?}", token_group_member);Ok(())}
Is this page helpful?