Key Parameters
MetadataPointer and TokenMetadata are configured together with these parameters:| Parameter | Description |
|---|---|
authority | Account authorized to update the metadata pointer address. |
metadataAddress | Account where metadata is stored. Set to the mint itself to keep metadata on-chain in a single account. |
updateAuthority | Account that can modify token metadata fields after initialization. |
name | Human-readable token name (e.g., “Example Token”). |
symbol | Short token symbol (e.g., “EXT”). |
uri | URL pointing to an external JSON file with extended metadata. |
additionalMetadata | Key-value pairs for custom descriptive fields. |
Use MetadataPointer and TokenMetadata With Light Token
Agent skill
Agent skill
Install the agent skill:See the AI tools guide for dedicated skills.
Report incorrect code
Copy
Ask AI
npx skills add https://zkcompression.com
- Guide
- AI Prompt
Setup
Setup
Report incorrect code
Copy
Ask AI
npm install @lightprotocol/compressed-token@beta \
@lightprotocol/stateless.js@beta \
@solana/spl-token
rpc, payer, mint, owner, recipient, and amount are defined.
See the full examples for runnable setup.Report incorrect code
Copy
Ask AI
import { createRpc } from "@lightprotocol/stateless.js";
const rpc = createRpc(RPC_ENDPOINT);
Create a Token-2022 Mint With Metadata
- Instruction
- Action
Report incorrect code
Copy
Ask AI
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,
getMintLen,
createInitializeMint2Instruction,
ExtensionType,
createInitializeMetadataPointerInstruction,
} from "@solana/spl-token";
import {
createInitializeInstruction as createInitializeTokenMetadataInstruction,
pack,
TokenMetadata,
} from "@solana/spl-token-metadata";
const rpc = createRpc(RPC_ENDPOINT);
const mintKeypair = Keypair.generate();
const decimals = 9;
const metadata: TokenMetadata = {
mint: mintKeypair.publicKey,
name: "Example Token",
symbol: "EXT",
uri: "https://example.com/metadata.json",
additionalMetadata: [],
};
// Calculate space for mint + MetadataPointer extension
const mintLen = getMintLen([ExtensionType.MetadataPointer]);
const metadataLen = pack(metadata).length;
const totalLen = mintLen + metadataLen;
const rentExemptBalance =
await rpc.getMinimumBalanceForRentExemption(totalLen);
// Create account
const createAccountIx = SystemProgram.createAccount({
fromPubkey: payer.publicKey,
lamports: rentExemptBalance,
newAccountPubkey: mintKeypair.publicKey,
programId: TOKEN_2022_PROGRAM_ID,
space: mintLen,
});
// Initialize MetadataPointer (points to the mint itself)
const initMetadataPointerIx = createInitializeMetadataPointerInstruction(
mintKeypair.publicKey,
payer.publicKey,
mintKeypair.publicKey, // metadata address = mint itself
TOKEN_2022_PROGRAM_ID
);
// Initialize mint
const initMintIx = createInitializeMint2Instruction(
mintKeypair.publicKey,
decimals,
payer.publicKey,
null,
TOKEN_2022_PROGRAM_ID
);
// Initialize TokenMetadata on the mint
const initTokenMetadataIx = createInitializeTokenMetadataInstruction({
programId: TOKEN_2022_PROGRAM_ID,
mint: mintKeypair.publicKey,
metadata: mintKeypair.publicKey,
mintAuthority: payer.publicKey,
name: metadata.name,
symbol: metadata.symbol,
uri: metadata.uri,
updateAuthority: payer.publicKey,
});
// Register interface PDA with Light Token
const createSplInterfaceIx = await LightTokenProgram.createSplInterface({
feePayer: payer.publicKey,
mint: mintKeypair.publicKey,
tokenProgramId: TOKEN_2022_PROGRAM_ID,
});
const tx = new Transaction().add(
createAccountIx,
initMetadataPointerIx,
initMintIx,
initTokenMetadataIx,
createSplInterfaceIx
);
const signature = await sendAndConfirmTransaction(rpc, tx, [
payer,
mintKeypair,
]);
Report incorrect code
Copy
Ask AI
import "dotenv/config";
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,
getMintLen,
createInitializeMint2Instruction,
ExtensionType,
createInitializeMetadataPointerInstruction,
} from "@solana/spl-token";
import {
createInitializeInstruction as createInitializeTokenMetadataInstruction,
pack,
TokenMetadata,
} from "@solana/spl-token-metadata";
import { homedir } from "os";
import { readFileSync } from "fs";
// devnet:
// const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`;
// const rpc = createRpc(RPC_URL);
// localnet:
const rpc = createRpc();
const payer = Keypair.fromSecretKey(
new Uint8Array(
JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8"))
)
);
(async function () {
const mintKeypair = Keypair.generate();
const decimals = 9;
const metadata: TokenMetadata = {
mint: mintKeypair.publicKey,
name: "Example Token",
symbol: "EXT",
uri: "https://example.com/metadata.json",
additionalMetadata: [],
};
// Calculate space for mint + MetadataPointer extension
const mintLen = getMintLen([ExtensionType.MetadataPointer]);
const metadataLen = pack(metadata).length;
const totalLen = mintLen + metadataLen;
const rentExemptBalance =
await rpc.getMinimumBalanceForRentExemption(totalLen);
// Instruction 1: Create account
const createAccountIx = SystemProgram.createAccount({
fromPubkey: payer.publicKey,
lamports: rentExemptBalance,
newAccountPubkey: mintKeypair.publicKey,
programId: TOKEN_2022_PROGRAM_ID,
space: mintLen,
});
// Instruction 2: Initialize MetadataPointer (points to the mint itself)
const initMetadataPointerIx =
createInitializeMetadataPointerInstruction(
mintKeypair.publicKey,
payer.publicKey,
mintKeypair.publicKey, // metadata address = mint itself
TOKEN_2022_PROGRAM_ID
);
// Instruction 3: Initialize mint
const initMintIx = createInitializeMint2Instruction(
mintKeypair.publicKey,
decimals,
payer.publicKey, // mint authority
null, // freeze authority
TOKEN_2022_PROGRAM_ID
);
// Instruction 4: Initialize TokenMetadata on the mint
const initTokenMetadataIx = createInitializeTokenMetadataInstruction({
programId: TOKEN_2022_PROGRAM_ID,
mint: mintKeypair.publicKey,
metadata: mintKeypair.publicKey,
mintAuthority: payer.publicKey,
name: metadata.name,
symbol: metadata.symbol,
uri: metadata.uri,
updateAuthority: payer.publicKey,
});
// Instruction 5: Create SPL interface PDA
// Holds Token-2022 tokens when wrapped to light-token
const createSplInterfaceIx = await LightTokenProgram.createSplInterface({
feePayer: payer.publicKey,
mint: mintKeypair.publicKey,
tokenProgramId: TOKEN_2022_PROGRAM_ID,
});
const tx = new Transaction().add(
createAccountIx,
initMetadataPointerIx,
initMintIx,
initTokenMetadataIx,
createSplInterfaceIx
);
const signature = await sendAndConfirmTransaction(rpc, tx, [
payer,
mintKeypair,
]);
console.log("Mint:", mintKeypair.publicKey.toBase58());
console.log("Tx:", signature);
})();
createMintInterface creates a basic Token 2022 mint with an interface PDA. To include the MetadataPointer and TokenMetadata extensions, use the instruction approach shown in the other tab.Create Interface PDA for Existing Mint
If you already have a Token-2022 mint with MetadataPointer and TokenMetadata, create an interface PDA with Light Token.Report incorrect code
Copy
Ask AI
import { LightTokenProgram } from "@lightprotocol/compressed-token";
import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token";
const createSplInterfaceIx = await LightTokenProgram.createSplInterface({
feePayer: payer.publicKey,
mint: mintKeypair.publicKey,
tokenProgramId: TOKEN_2022_PROGRAM_ID,
});
Create a Token-2022 mint with MetadataPointer and TokenMetadata and register with Light Token
Report incorrect code
Copy
Ask AI
---
description: Create a Token-2022 mint with MetadataPointer and TokenMetadata and register with Light Token
allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression
---
## Create a Token-2022 mint with MetadataPointer and TokenMetadata and register with Light Token
Context:
- Guide: https://zkcompression.com/light-token/extensions/metadata-and-metadata-pointer
- Skills and resources index: https://zkcompression.com/skill.md
- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison
- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token, @solana/spl-token-metadata
SPL equivalent: createInitializeMetadataPointerInstruction() + createInitializeTokenMetadataInstruction()
Light Token: createInitializeMetadataPointerInstruction() + createInitializeTokenMetadataInstruction() + LightTokenProgram.createSplInterface()
### 1. Index project
- Grep `@solana/spl-token|Connection|Keypair|MetadataPointer|TOKEN_2022` across src/
- Glob `**/*.ts` for project structure
- Identify: RPC setup, existing mint logic, entry point for T22 mint with metadata extension
- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel
### 2. Read references
- WebFetch the guide above — follow the Instruction tab for the full flow
- WebFetch skill.md — check for a dedicated skill and resources matching this task
- TaskCreate one todo per phase below to track progress
### 3. Clarify intention
- AskUserQuestion: what is the goal? (new T22 mint with metadata, register existing T22 mint, migrate existing SPL code)
- AskUserQuestion: does the project already use Token-2022?
- Summarize findings and wait for user confirmation before implementing
### 4. Create plan
- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes
- Verify existing connection/signer setup is compatible with the cookbook prerequisites
- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion)
- Present the plan to the user for approval before proceeding
### 5. Implement
- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token @solana/spl-token-metadata`
- Create T22 mint: getMintLen([ExtensionType.MetadataPointer]) → SystemProgram.createAccount → createInitializeMetadataPointerInstruction → createInitializeMint2Instruction → createInitializeTokenMetadataInstruction
- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID })
- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified
- Write/Edit to create or modify files
- TaskUpdate to mark each step done
### 6. Verify
- Bash `tsc --noEmit`
- Bash run existing test suite if present
- TaskUpdate to mark complete
### Tools
- mcp__zkcompression__SearchLightProtocol("<query>") for API details
- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "<q>") for architecture
- Task subagent with Grep/Read/WebFetch for parallel lookups
- TaskList to check remaining work