Skip to main content
A designated authority gains irrevocable transfer and burn rights over every token account for a mint, set once at initialization and enforced permanently.
Set the compression_only flag when creating token accounts for this mint. Use transferInterface for transfers as usual.

Key Parameters

PermanentDelegate is configured with one parameter:
ParameterDescription
delegateThe public key granted permanent, irrevocable transfer and burn authority over all token accounts for this mint.
Unlike standard delegates set per token account, the permanent delegate operates at the mint level. Token account owners cannot revoke this authority. Only the current permanent delegate can reassign the role to a new account.

Use PermanentDelegate 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 a Token-2022 Mint With Permanent Delegate

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,
    createInitializePermanentDelegateInstruction,
} from "@solana/spl-token";

const rpc = createRpc(RPC_ENDPOINT);

const mintKeypair = Keypair.generate();
const decimals = 9;

// Calculate space for mint + PermanentDelegate extension
const mintLen = getMintLen([ExtensionType.PermanentDelegate]);
const rentExemptBalance =
    await rpc.getMinimumBalanceForRentExemption(mintLen);

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

// Initialize PermanentDelegate extension
const initPermanentDelegateIx = createInitializePermanentDelegateInstruction(
    mintKeypair.publicKey,
    payer.publicKey, // permanent delegate authority
    TOKEN_2022_PROGRAM_ID,
);

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

// 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,
    initPermanentDelegateIx,
    initMintIx,
    createSplInterfaceIx
);

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

Create Interface PDA for Existing Mint

If you already have a Token-2022 mint with PermanentDelegate, create an interface PDA with Light Token.
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,
});

Transfer interface

Wrap and unwrap


Didn’t find what you were looking for?

Reach out! Telegram | email | Discord