Skip to main content
Organize tokens into hierarchical groups such as NFT collections by linking a group mint to one or more member mints through on-chain pointer and data extensions.

Key Parameters

Token groups use four related extensions that work in pairs:
ExtensionParametersDescription
GroupPointerauthority, groupAddressDesignates a mint as a group mint by pointing to an account that stores group configuration. Typically points to the mint itself.
TokenGroupupdateAuthority, mint, size, maxSizeStores the group metadata (update authority, current member count, maximum size) directly on the mint account.
GroupMemberPointerauthority, memberAddressDesignates a mint as a member mint by pointing to an account that stores membership data. Typically points to the mint itself.
TokenGroupMembermint, group, memberNumberStores the membership data (parent group address, sequential member number) directly on the mint account.

Use Token Groups With Light Token

Install the agent skill:
npx skills add https://zkcompression.com
See the AI tools guide for dedicated skills.
npm install @lightprotocol/compressed-token@beta \
            @lightprotocol/stateless.js@beta \
            @solana/spl-token
Snippets below assume rpc, payer, mint, owner, recipient, and amount are defined. See the full examples for runnable setup.
import { createRpc } from "@lightprotocol/stateless.js";

const rpc = createRpc(RPC_ENDPOINT);

Create Group Mint

Create a Token-2022 mint with the GroupPointer and TokenGroup extensions.
import {
    Keypair,
    SystemProgram,
    Transaction,
    sendAndConfirmTransaction,
} from "@solana/web3.js";
import { createRpc } from "@lightprotocol/stateless.js";
import { LightTokenProgram } from "@lightprotocol/compressed-token";
import {
    TOKEN_2022_PROGRAM_ID,
    ExtensionType,
    getMintLen,
    createInitializeMint2Instruction,
    createInitializeGroupPointerInstruction,
    createInitializeGroupInstruction,
} from "@solana/spl-token";

const rpc = createRpc(RPC_ENDPOINT);

const groupMintKeypair = Keypair.generate();
const decimals = 0;

// Calculate space including GroupPointer and TokenGroup extensions
const mintLen = getMintLen([ExtensionType.GroupPointer, ExtensionType.TokenGroup]);
const rentExemptBalance = await rpc.getMinimumBalanceForRentExemption(mintLen);

// Create the mint account
const createMintAccountIx = SystemProgram.createAccount({
    fromPubkey: payer.publicKey,
    lamports: rentExemptBalance,
    newAccountPubkey: groupMintKeypair.publicKey,
    programId: TOKEN_2022_PROGRAM_ID,
    space: mintLen,
});

// Initialize GroupPointer (points to the mint itself)
const initGroupPointerIx = createInitializeGroupPointerInstruction(
    groupMintKeypair.publicKey,
    payer.publicKey, // authority
    groupMintKeypair.publicKey, // group address (self-referencing)
    TOKEN_2022_PROGRAM_ID,
);

// Initialize the mint
const initMintIx = createInitializeMint2Instruction(
    groupMintKeypair.publicKey,
    decimals,
    payer.publicKey, // mint authority
    null, // freeze authority
    TOKEN_2022_PROGRAM_ID,
);

// Initialize the TokenGroup data on the mint
const initGroupIx = createInitializeGroupInstruction({
    group: groupMintKeypair.publicKey,
    maxSize: 100,
    mint: groupMintKeypair.publicKey,
    mintAuthority: payer.publicKey,
    programId: TOKEN_2022_PROGRAM_ID,
    updateAuthority: payer.publicKey,
});

const tx = new Transaction().add(
    createMintAccountIx,
    initGroupPointerIx,
    initMintIx,
    initGroupIx,
);

const signature = await sendAndConfirmTransaction(rpc, tx, [
    payer,
    groupMintKeypair,
]);

Create Member Mint

Create a member mint with the GroupMemberPointer and TokenGroupMember extensions, linking it to the group mint.
import {
    createInitializeGroupMemberPointerInstruction,
    createInitializeMemberInstruction,
} from "@solana/spl-token";

const memberMintKeypair = Keypair.generate();

// Calculate space including GroupMemberPointer and TokenGroupMember extensions
const memberMintLen = getMintLen([
    ExtensionType.GroupMemberPointer,
    ExtensionType.TokenGroupMember,
]);
const memberRentExemptBalance = await rpc.getMinimumBalanceForRentExemption(memberMintLen);

// Create the member mint account
const createMemberMintIx = SystemProgram.createAccount({
    fromPubkey: payer.publicKey,
    lamports: memberRentExemptBalance,
    newAccountPubkey: memberMintKeypair.publicKey,
    programId: TOKEN_2022_PROGRAM_ID,
    space: memberMintLen,
});

// Initialize GroupMemberPointer (points to the member mint itself)
const initMemberPointerIx = createInitializeGroupMemberPointerInstruction(
    memberMintKeypair.publicKey,
    payer.publicKey, // authority
    memberMintKeypair.publicKey, // member address (self-referencing)
    TOKEN_2022_PROGRAM_ID,
);

// Initialize the member mint
const initMemberMintIx = createInitializeMint2Instruction(
    memberMintKeypair.publicKey,
    0,
    payer.publicKey, // mint authority
    null, // freeze authority
    TOKEN_2022_PROGRAM_ID,
);

// Initialize the TokenGroupMember data on the member mint
const initMemberIx = createInitializeMemberInstruction({
    group: groupMintKeypair.publicKey,
    groupUpdateAuthority: payer.publicKey,
    member: memberMintKeypair.publicKey,
    memberMint: memberMintKeypair.publicKey,
    memberMintAuthority: payer.publicKey,
    programId: TOKEN_2022_PROGRAM_ID,
});

const memberTx = new Transaction().add(
    createMemberMintIx,
    initMemberPointerIx,
    initMemberMintIx,
    initMemberIx,
);

await sendAndConfirmTransaction(rpc, memberTx, [payer, memberMintKeypair]);

Create Interface PDA for Existing Mints

Create interface PDAs for both the group mint and member mint with Light Token.
// Register group mint
const registerGroupIx = await LightTokenProgram.createSplInterface({
    feePayer: payer.publicKey,
    mint: groupMintKeypair.publicKey,
    tokenProgramId: TOKEN_2022_PROGRAM_ID,
});

// Register member mint
const registerMemberIx = await LightTokenProgram.createSplInterface({
    feePayer: payer.publicKey,
    mint: memberMintKeypair.publicKey,
    tokenProgramId: TOKEN_2022_PROGRAM_ID,
});

const registerTx = new Transaction().add(registerGroupIx, registerMemberIx);
await sendAndConfirmTransaction(rpc, registerTx, [payer]);

Transfer interface

Wrap and unwrap


Didn’t find what you were looking for?

Reach out! Telegram | email | Discord