مجموعات الرموز والأعضاء

ما هي ملحقات المجموعة وعضو المجموعة؟

المجموعة هي عملية سك تمثل مجموعة. عضو المجموعة هو عملية سك تنتمي إلى تلك المجموعة.

استخدم هذه الملحقات عندما يجب أن تمثل إحدى عمليات السك المجموعة وأن تمثل عمليات السك الأخرى العناصر التي تنتمي إليها.

يمكن لبرنامج Token Extensions تخزين بيانات مجموعة الرموز مباشرة على عملية السك باستخدام أربعة ملحقات ذات صلة:

  • GroupPointer يوجه عملية السك إلى الحساب الذي يخزن بيانات المجموعة.
  • TokenGroup يخزن بيانات المجموعة نفسها، بما في ذلك سلطة التحديث والحجم الحالي والحجم الأقصى.
  • GroupMemberPointer يوجه عملية السك إلى الحساب الذي يخزن بيانات العضو.
  • TokenGroupMember يخزن عنوان مجموعة العضو ورقم العضو.

يمكن لـ GroupPointer و GroupMemberPointer الإشارة إلى أي حساب مملوك لبرنامج يطبق واجهة مجموعة الرموز.

يطبق برنامج Token Extensions أيضًا تلك الواجهة مباشرة من خلال ملحقات السك TokenGroup و TokenGroupMember.

كيفية إنشاء مجموعات وأعضاء مخزنة على حساب السك

لإنشاء مجموعات وأعضاء مخزنة على حساب السك:

  1. أنشئ حساب سك المجموعة وابدأ تشغيل GroupPointer.
  2. ابدأ تشغيل سك المجموعة باستخدام InitializeMint.
  3. ابدأ تشغيل TokenGroup على نفس عملية السك.
  4. أنشئ حساب سك العضو وابدأ تشغيل GroupMemberPointer.
  5. ابدأ تشغيل سك العضو باستخدام InitializeMint.
  6. ابدأ تشغيل TokenGroupMember على نفس عملية السك بحيث يشير إلى سك المجموعة.

احسب حجم الصك الجماعي والإيجار

احسب الحجم والإيجار المطلوبين للصك الجماعي.

إنشاء وتهيئة الصك الجماعي

أنشئ حساب الصك الجماعي، وهيئ GroupPointer، وهيئ الصك، وهيئ TokenGroup في معاملة واحدة.

احسب حجم صك العضو والإيجار

احسب الحجم والإيجار المطلوبين لصك العضو.

إنشاء وتهيئة صك العضو

أنشئ حساب صك العضو، وهيئ GroupMemberPointer، وهيئ الصك، وهيئ TokenGroupMember في معاملة واحدة.

احسب حجم الصك الجماعي والإيجار

احسب الحجم والإيجار المطلوبين للصك الجماعي.

إنشاء وتهيئة الصك الجماعي

أنشئ حساب الصك الجماعي، وهيئ GroupPointer، وهيئ الصك، وهيئ TokenGroup في معاملة واحدة.

احسب حجم صك العضو والإيجار

احسب الحجم والإيجار المطلوبين لصك العضو.

إنشاء وتهيئة صك العضو

أنشئ حساب صك العضو، وهيئ GroupMemberPointer، وهيئ الصك، وهيئ TokenGroupMember في معاملة واحدة.

Example
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();

المؤشرات وترتيب التعليمات

يخزن GroupPointer و GroupMemberPointer عنوان الحساب حيث تتواجد بيانات المجموعة أو العضو. يخزن TokenGroup و TokenGroupMember بيانات المجموعة أو العضو الفعلية.

يجب أن يأتي GroupPointerInstruction::Initialize و GroupMemberPointerInstruction::Initialize قبل InitializeMint. يجب أن يأتي TokenGroupInstruction::InitializeGroup و TokenGroupInstruction::InitializeMember بعد InitializeMint. لكل صك، يجب تضمين CreateAccount وتعليمة تهيئة المؤشر و InitializeMint في نفس المعاملة.

مرجع المصدر

GroupPointer و GroupMemberPointer هما تعليمات مؤشر في برنامج Token Extensions. يتبع TokenGroup و TokenGroupMember واجهة مجموعة الرموز، والتي ينفذها برنامج Token Extensions.

مؤشر المجموعة ومؤشر عضو المجموعة

العنصرالوصفالمصدر
GroupPointerامتداد صك يخزن الصلاحية والعنوان للحساب الذي يخزن بيانات المجموعة.المصدر
GroupMemberPointerامتداد صك يخزن الصلاحية والعنوان للحساب الذي يخزن بيانات العضو.المصدر
GroupPointerInstruction::Initializeيهيئ امتداد مؤشر المجموعة قبل InitializeMint.المصدر
GroupPointerInstruction::Updateيحدّث عنوان المجموعة المخزن بواسطة امتداد GroupPointer للصك.المصدر
GroupMemberPointerInstruction::Initializeيهيئ امتداد مؤشر عضو المجموعة قبل InitializeMint.المصدر
GroupMemberPointerInstruction::Updateيحدّث عنوان العضو المخزن بواسطة امتداد GroupMemberPointer للصك.المصدر
process_initialize (GroupPointer)يكتب صلاحية GroupPointer الأولية وعنوان المجموعة على الصك.المصدر
process_update (GroupPointer)يتحقق من صلاحية مؤشر المجموعة، ثم يعيد كتابة عنوان المجموعة المخزن في الصك.المصدر
process_initialize (GroupMemberPointer)يكتب صلاحية GroupMemberPointer الأولية وعنوان العضو على الصك.المصدر
process_update (GroupMemberPointer)يتحقق من صلاحية مؤشر عضو المجموعة، ثم يعيد كتابة عنوان العضو المخزن في الصك.المصدر

مجموعة الرموز وعضو مجموعة الرموز

العنصرالوصفالمصدر
TokenGroupحالة واجهة مجموعة الرموز المخزنة على عملية السك، بما في ذلك سلطة التحديث والحجم الحالي والحجم الأقصى.المصدر
TokenGroupMemberحالة واجهة عضو مجموعة الرموز المخزنة على عملية السك، بما في ذلك عملية سك العضو وعنوان المجموعة ورقم العضو.المصدر
TokenGroupInstruction::InitializeGroupتعليمات واجهة مجموعة الرموز المدعومة من قبل Token Extensions Program لتهيئة مجموعة جديدة لعملية سك تم تهيئتها بالفعل.المصدر
TokenGroupInstruction::UpdateGroupMaxSizeتعليمات واجهة مجموعة الرموز المدعومة من قبل Token Extensions Program لتحديث الحد الأقصى لعدد الأعضاء المسموح بهم في المجموعة.المصدر
TokenGroupInstruction::UpdateGroupAuthorityتعليمات واجهة مجموعة الرموز المدعومة من قبل Token Extensions Program لتدوير أو إلغاء سلطة التحديث الخاصة بالمجموعة.المصدر
TokenGroupInstruction::InitializeMemberتعليمات واجهة مجموعة الرموز المدعومة من قبل Token Extensions Program لتهيئة عضو جديد لمجموعة تم تهيئتها بالفعل.المصدر
process_initialize_groupيتحقق من صحة عملية السك، ويتأكد من وجود GroupPointer، ويخصص حالة TokenGroup على عملية سك المجموعة.المصدر
process_update_group_max_sizeيتحقق من صحة سلطة التحديث الحالية، ثم يحدث الحجم الأقصى للمجموعة.المصدر
process_update_group_authorityيتحقق من صحة سلطة التحديث الحالية، ثم يدور أو يلغي سلطة التحديث الخاصة بالمجموعة.المصدر
process_initialize_memberيتحقق من صحة عملية سك العضو وسلطة المجموعة، ويزيد حجم المجموعة، ويخصص حالة TokenGroupMember على عملية السك.المصدر

تايب سكريبت

يستخدم المثال أدناه باستخدام Kit التعليمات المُنشأة مباشرة. تم تضمين الأمثلة القديمة التي تستخدم @solana/web3.js و @solana/spl-token ومساعدات مجموعة الرموز للمرجعية.

Kit

Instructions
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
)
);
Console
Click to execute the code.

Web3.js

Instructions
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
)
);
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_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(())
}
Console
Click to execute the code.

Is this page helpful?

تدار بواسطة

© 2026 مؤسسة سولانا.
جميع الحقوق محفوظة.
تواصل معنا