Skip to main content

Key Concepts

The TransferFeeExtension enables automatic fee collection on every token transfer. Fees accumulate in the recipient token accounts and can be withdrawn by the withdraw authority set on the mint account. Transfer fees are configured with four parameters:
ParameterDescription
transferFeeBasisPointsFee percentage in basis points (100 = 1%). Must be zero for Light Token.
maximumFeeUpper limit on the fee charged per transfer, in token base units. Must be zero for Light Token.
transferFeeConfigAuthorityAuthority that can modify fee settings.
withdrawWithheldAuthorityAuthority that can collect accumulated fees from recipient accounts.

Use TransferFeeConfig 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 Transfer Fees

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

const rpc = createRpc(RPC_ENDPOINT);

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

// Calculate space for mint + TransferFeeConfig extension
const mintLen = getMintLen([ExtensionType.TransferFeeConfig]);
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 TransferFeeConfig with zero fees
const initTransferFeeIx = createInitializeTransferFeeConfigInstruction(
    mintKeypair.publicKey,
    payer.publicKey, // transfer fee config authority
    payer.publicKey, // withdraw withheld authority
    0,               // fee basis points (must be zero)
    BigInt(0),       // maximum fee (must be zero)
    TOKEN_2022_PROGRAM_ID
);

// Initialize mint
const initMintIx = createInitializeMint2Instruction(
    mintKeypair.publicKey,
    decimals,
    payer.publicKey,
    null,
    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,
    initTransferFeeIx,
    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 a zero-fee TransferFeeConfig, 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