The Group and Member Extension
The Group
and Member
extensions are Mint
account extensions that introduce the ability to create groups, like collections for NFTs, that are linked with multiple assets.
Initializing the Mint Account
The Member
and Group
extension are a little different from what we're used to doing because it's composed of 2 different extensions that both go on a Mint
account:
- The
Extension
that contains all the information about the group or member. - The
Pointer Extension
that references theMint
account where theGroup
orMember
extension lives.
Usually, when used, the Extension
and the Pointer Extension
live on the same Mint
account; and we're going to do the same for this example.
Let's start with some basics before diving into the code:
While the GroupPointer
and MemberPointer
extension lives in the @solana/spl-token
package, to initialize the Group
and Member
we need to use the @solana/spl-token-group
package.
So let's install the required package:
npm i @solana/spl-token-group
Additionally, the Group
and Member
extension is one of the "only" extensions that requires you to initialize the extension after having initialized the Mint
account.
This is because the metadata initialization instruction dynamically allocates the required space for the length of the group and member content.
At the same time, this means that we're going to need to initialize the Mint
account with enough lamports to be rent exempt with the Group
or Member
extension included, but allocating enough space only for the GroupPointer
or MemberPointer
extension since the token_group_initialize()
and token_group_member_initialize()
instruction actually increases the space correctly.
In the code initializing the Group
looks like this:
const mint = Keypair.generate();
// Size of Mint Account with extensions
const mintLen = getMintLen([ExtensionType.GroupPointer]);
// Minimum lamports required for Mint Account
const lamports = await connection.getMinimumBalanceForRentExemption(mintLen + TYPE_SIZE + LENGTH_SIZE + TOKEN_GROUP_SIZE);
const createAccountInstruction = SystemProgram.createAccount({
fromPubkey: keypair.publicKey,
newAccountPubkey: mint.publicKey,
space: mintLen,
lamports,
programId: TOKEN_2022_PROGRAM_ID,
});
const initializeGroupPointer = createInitializeGroupPointerInstruction(
mint.publicKey,
keypair.publicKey,
mint.publicKey,
TOKEN_2022_PROGRAM_ID,
);
const initializeMintInstruction = createInitializeMintInstruction(
mint.publicKey,
6,
keypair.publicKey,
null,
TOKEN_2022_PROGRAM_ID,
);
const initializeGroupInstruction = createInitializeGroupInstruction(
{
programId: TOKEN_2022_PROGRAM_ID,
group: mint.publicKey,
mint: mint.publicKey,
mintAuthority: keypair.publicKey,
updateAuthority: keypair.publicKey,
maxSize: BigInt(100),
}
);
const transaction = new Transaction().add(
createAccountInstruction,
initializeGroupPointer,
initializeMintInstruction,
initializeGroupInstruction,
);
const signature = await sendAndConfirmTransaction(connection, transaction, [keypair, mint], {commitment: "finalized"});
console.log(`Mint created! Check out your TX here: https://explorer.solana.com/tx/${signature}?cluster=devnet`);
And after this, we can use the group that we just created to add a member to it like this:
const member = Keypair.generate();
// Size of Member Account with extensions
const memberLen = getMintLen([ExtensionType.GroupMemberPointer]);
// Minimum lamports required for Member Account
const lamports = await connection.getMinimumBalanceForRentExemption(memberLen + TYPE_SIZE + LENGTH_SIZE + TOKEN_GROUP_MEMBER_SIZE);
const createAccountInstruction = SystemProgram.createAccount({
fromPubkey: keypair.publicKey,
newAccountPubkey: member.publicKey,
space: memberLen,
lamports,
programId: TOKEN_2022_PROGRAM_ID,
});
const initializeGroupMemberPointer = createInitializeGroupMemberPointerInstruction(
member.publicKey,
keypair.publicKey,
member.publicKey,
TOKEN_2022_PROGRAM_ID,
);
const initializeMintInstruction = createInitializeMintInstruction(
member.publicKey,
6,
keypair.publicKey,
null,
TOKEN_2022_PROGRAM_ID,
);
const initializeGroupMemberInstruction = createInitializeMemberInstruction(
{
programId: TOKEN_2022_PROGRAM_ID,
group: mint.publicKey,
member: member.publicKey,
memberMint: member.publicKey,
memberMintAuthority: keypair.publicKey,
groupUpdateAuthority: keypair.publicKey,
}
);
const transaction = new Transaction().add(
createAccountInstruction,
initializeGroupMemberPointer,
initializeMintInstruction,
initializeGroupMemberInstruction,
);
const signature = await sendAndConfirmTransaction(connection, transaction, [keypair, member], {commitment: "finalized"});
console.log(`Member created! Check out your TX here: https://explorer.solana.com/tx/${signature}?cluster=devnet`);