Token-2022 module configuration: the complete reference
July 1, 2026 · 12 min read · Kept current with SPL Token-2022
This page is a configuration reference for Solana Token-2022 (also called SPL Token Extensions) — the token program at address TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb. It covers the extensions Smeltr exposes as deployment modules: Transfer Fee, Non-Transferable, Permanent Delegate, and on-chain TokenMetadata. Every parameter, valid range, authority field, and compatibility rule below reflects the on-chain program's behavior, not Smeltr-specific conventions.
The one rule that governs everything
Extensions must be initialized before InitializeMint, inside the same transaction that creates the mint account. The mint account's size is fixed at allocation to fit exactly the extensions you selected. After InitializeMint executes, no further extensions can be added — there is no "upgrade" path. If you deploy without Transfer Fee, that token can never charge transfer fees. Plan the full extension set before deployment.
The canonical instruction order for a Token-2022 mint deployment is:
SystemProgram.createAccount— allocate the mint account, sized for all selected extensions, owned by the Token-2022 program- Each extension's initialization instruction (any order among themselves for the extensions on this page)
InitializeMetadataPointer— if using on-chain metadataInitializeMint— finalizes the mint; decimals, mint authority, and freeze authority are set here
Transfer Fee (TransferFeeConfig)
Charges a protocol-enforced fee on every transfer of the token. The fee is withheld on the recipient's token account in the transferred token (never in SOL), and sits there until the withdraw authority harvests it. No off-chain infrastructure is involved — the Solana runtime enforces collection.
| Parameter | Type / range | Notes |
|---|---|---|
| transferFeeBasisPoints | u16, 0–10,000 | 1 bps = 0.01%. 10,000 = 100%. Typical range for legitimate projects: 10–500 (0.1%–5%). |
| maximumFee | u64, base units | Hard cap per transfer, denominated in the token's base units (before decimals). Set to u64::MAX for "no cap". A low cap effectively converts the percentage fee into a flat fee for large transfers. |
| transferFeeConfigAuthority | Pubkey or none | Can change the fee later (takes effect after ~2 epochs). Set to none to make the fee permanent. |
| withdrawWithheldAuthority | Pubkey or none | The only address that can harvest withheld fees. If none, withheld fees are permanently unrecoverable. |
Common mistake: forgetting that recipients receive less than the sent amount. Integrations that assert received == sent (some DEX pools, payment processors) break against transfer-fee tokens. Use transferChecked semantics and account for the fee.
Non-Transferable (soul-bound)
Tokens minted into an account can never be transferred out of it — enforced by the program on every transfer path. There are no parameters to configure; the extension is a flag on the mint.
- Holders can still burn their tokens and close their accounts — soul-bound is not seize-proof custody, it is transfer prevention.
- Use cases: credentials, certifications, memberships, achievement badges, reputation systems.
- Combining with Transfer Fee is legal at the protocol level but pointless — no transfers can ever occur to charge a fee on. Smeltr surfaces this as a soft-conflict warning.
Permanent Delegate
Grants one address unconditional authority to transfer or burn any holder's balance of this token, forever, with no holder consent and no revocation. It is the most powerful extension in Token-2022 and the one most often misused.
| Parameter | Type | Notes |
|---|---|---|
| delegate | Pubkey | Cannot be changed or removed after InitializeMint. Choose a governance-controlled or multisig address for legitimate deployments. |
Legitimate uses: regulatory compliance (court-ordered seizure), subscription revocation, expirable game assets, RWA clawback requirements. Disclosure is the ethical line: holders must be able to discover that a permanent delegate exists before they acquire the token. It is visible on-chain in the mint account's extension data — explorers and wallets increasingly surface it.
On-chain metadata (TokenMetadata + MetadataPointer)
Token-2022 supports name/symbol/URI metadata stored in the mint account itself — no Metaplex account needed. Two pieces cooperate: MetadataPointer (initialized before InitializeMint, pointing at the mint itself) and the TokenMetadata TLV data (written after InitializeMint).
Because the metadata is written after mint initialization but enlarges the account, the deployment must either pre-fund the mint account with enough lamports for the eventual size (Smeltr's approach — a two-transaction flow) or perform a reallocation. Metadata fields: name (≤32 chars as enforced by common wallets), symbol (≤10), uri (typically an Arweave/IPFS JSON document with image and description). The update authority can rewrite metadata later unless set to none.
Compatibility matrix
| Combination | Valid? | Notes |
|---|---|---|
| Transfer Fee + Permanent Delegate | ✓ | Delegate transfers also incur the fee. |
| Transfer Fee + Non-Transferable | ✓ (discouraged) | Legal but inert — no transfers ever occur. |
| Non-Transferable + Permanent Delegate | ✓ | Delegate can still burn/move despite non-transferability — the delegate authority supersedes the transfer block. Disclose clearly. |
| Any module + TokenMetadata | ✓ | MetadataPointer must not collide with another pointer configuration. |
| Same extension twice | ✗ | Duplicate extension initialization fails at the program level. |
Authority security model
Every authority field is an attack surface. A trustworthy deployment tool should enforce:
- User-owned authorities only. Mint authority, freeze authority, fee authorities, and the permanent delegate should belong to the deployer (or their governance), never to the deployment platform. Smeltr enforces this with a platform-key denylist checked on every authority field before instructions are built.
- Explicit none is better than a forgotten key. Setting freeze authority or fee-config authority to none permanently disables that power — often the right call for community tokens.
- The mint keypair is ephemeral. It signs once at creation and should then be discarded; ongoing control flows through the authority fields, not the mint key.
Quick answers
Can I add an extension to an existing token? No. Extensions are fixed at mint creation.
Can the transfer fee be changed later? Yes, by the fee-config authority (effective after ~2 epochs) — unless that authority was set to none.
Are Token-2022 tokens compatible with regular SPL tooling? Mostly, via the shared interface — but integrations must use the Token-2022 program ID and transferChecked; some older dApps only support the legacy token program.
Is the fee paid in SOL? No — transfer fees are withheld in the token being transferred. Only network (gas) fees are paid in SOL.
Deploy it without writing code: Smeltr composes these modules with compatibility checks, authority denylisting, and transparent per-deployment pricing — smeltr.org/deploy. You sign every transaction with your own wallet; Smeltr never holds keys or authorities.