Групи токенів та їх учасники

Що таке розширення Group та Group Member?

Група — це mint, який представляє колекцію. Член групи — це mint, який належить до цієї колекції.

Використовуйте ці розширення, коли один mint має представляти колекцію, а інші mint-акаунти мають представляти елементи, що належать до неї.

Token Extensions Program може зберігати дані групи токенів безпосередньо на mint-акаунті за допомогою чотирьох пов'язаних розширень:

  • GroupPointer вказує mint на акаунт, який зберігає дані групи.
  • TokenGroup зберігає самі дані групи, включаючи орган оновлення, поточний розмір та максимальний розмір.
  • GroupMemberPointer вказує mint на акаунт, який зберігає дані члена.
  • TokenGroupMember зберігає адресу групи члена та номер члена.

GroupPointer та GroupMemberPointer можуть посилатися на будь-який акаунт, що належить програмі, яка реалізує інтерфейс Token group.

Token Extensions Program також реалізує цей інтерфейс безпосередньо через розширення mint TokenGroup та TokenGroupMember.

Як створити групи та членів, що зберігаються на mint account

Щоб створити групи та членів, що зберігаються на mint account:

  1. Створіть груповий mint account і ініціалізуйте GroupPointer.
  2. Ініціалізуйте груповий mint за допомогою InitializeMint.
  3. Ініціалізуйте TokenGroup на тому ж mint.
  4. Створіть mint account члена і ініціалізуйте GroupMemberPointer.
  5. Ініціалізуйте mint члена за допомогою InitializeMint.
  6. Ініціалізуйте TokenGroupMember на тому ж mint, щоб він посилався на груповий mint.

Обчислення розміру та рент для групового mint

Обчисліть розмір та рент, необхідні для групового mint.

Створення та ініціалізація групового Mint

Створіть обліковий запис групового mint, ініціалізуйте GroupPointer, ініціалізуйте mint та ініціалізуйте TokenGroup в одній транзакції.

Обчислення розміру та рент для mint учасника

Обчисліть розмір та рент, необхідні для mint учасника.

Створення та ініціалізація Mint учасника

Створіть обліковий запис mint учасника, ініціалізуйте GroupMemberPointer, ініціалізуйте mint та ініціалізуйте TokenGroupMember в одній транзакції.

Обчислення розміру та рент для групового mint

Обчисліть розмір та рент, необхідні для групового mint.

Створення та ініціалізація групового Mint

Створіть обліковий запис групового mint, ініціалізуйте GroupPointer, ініціалізуйте mint та ініціалізуйте TokenGroup в одній транзакції.

Обчислення розміру та рент для mint учасника

Обчисліть розмір та рент, необхідні для mint учасника.

Створення та ініціалізація Mint учасника

Створіть обліковий запис mint учасника, ініціалізуйте GroupMemberPointer, ініціалізуйте mint та ініціалізуйте 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. Для кожного mint, CreateAccount, інструкція ініціалізації покажчика та InitializeMint мають бути включені в одну транзакцію.

Довідка по вихідному коду

GroupPointer та GroupMemberPointer є інструкціями покажчика в Token Extensions Program. TokenGroup та TokenGroupMember відповідають інтерфейсу Token group, який реалізує Token Extensions Program.

Покажчик групи та покажчик учасника групи

ЕлементОписДжерело
GroupPointerРозширення mint, яке зберігає повноваження та адресу облікового запису, що містить дані групи.Джерело
GroupMemberPointerРозширення mint, яке зберігає повноваження та адресу облікового запису, що містить дані учасника.Джерело
GroupPointerInstruction::InitializeІніціалізує розширення покажчика групи перед InitializeMint.Джерело
GroupPointerInstruction::UpdateОновлює адресу групи, збережену розширенням GroupPointer mint.Джерело
GroupMemberPointerInstruction::InitializeІніціалізує розширення покажчика учасника групи перед InitializeMint.Джерело
GroupMemberPointerInstruction::UpdateОновлює адресу учасника, збережену розширенням GroupMemberPointer mint.Джерело
process_initialize (GroupPointer)Записує початкові повноваження GroupPointer та адресу групи на mint.Джерело
process_update (GroupPointer)Перевіряє повноваження покажчика групи, потім перезаписує збережену адресу групи mint.Джерело
process_initialize (GroupMemberPointer)Записує початкові повноваження GroupMemberPointer та адресу учасника на mint.Джерело
process_update (GroupMemberPointer)Перевіряє повноваження покажчика учасника групи, потім перезаписує збережену адресу учасника mint.Джерело

Група токенів та учасник групи токенів

ЕлементОписДжерело
TokenGroupСтан інтерфейсу групи токенів, що зберігається в mint, включаючи орган оновлення, поточний розмір та максимальний розмір.Джерело
TokenGroupMemberСтан інтерфейсу учасника групи токенів, що зберігається в mint, включаючи mint учасника, адресу групи та номер учасника.Джерело
TokenGroupInstruction::InitializeGroupІнструкція інтерфейсу групи токенів, що підтримується Token Extensions Program для ініціалізації нової групи для вже ініціалізованого mint.Джерело
TokenGroupInstruction::UpdateGroupMaxSizeІнструкція інтерфейсу групи токенів, що підтримується Token Extensions Program для оновлення максимальної кількості учасників, дозволених у групі.Джерело
TokenGroupInstruction::UpdateGroupAuthorityІнструкція інтерфейсу групи токенів, що підтримується Token Extensions Program для ротації або скасування органу оновлення групи.Джерело
TokenGroupInstruction::InitializeMemberІнструкція інтерфейсу групи токенів, що підтримується Token Extensions Program для ініціалізації нового учасника для вже ініціалізованої групи.Джерело
process_initialize_groupПеревіряє mint, підтверджує наявність GroupPointer та виділяє стан TokenGroup для групового mint.Джерело
process_update_group_max_sizeПеревіряє поточний орган оновлення, потім оновлює максимальний розмір групи.Джерело
process_update_group_authorityПеревіряє поточний орган оновлення, потім виконує ротацію або скасовує орган оновлення групи.Джерело
process_initialize_memberПеревіряє mint учасника та орган групи, збільшує розмір групи та виділяє стан TokenGroupMember для mint.Джерело

Typescript

Наведений нижче приклад 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 Фонд Solana.
Всі права захищені.
Залишайтеся на зв'язку