Typescript
Token2022 with Web3.js

Token2022 with Web3.js

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 the Mint account where the Group or Member 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.

The Group and Member extension can't be on the same account

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`);
Contents
View Source
Blueshift © 2025Commit: 538ee5b