Token-2022 vs legacy SPL Token: what changed and why it matters for rent recovery

Published 2026-09-28 · 6 min read

Token-2022 vs legacy SPL Token: what changed and why it matters for rent recovery

Solana quietly rolled out Token-2022 (formerly called "SPL Token 2022" or "Token Extensions") in late 2023. As of 2026, it's used by a growing share of new token launches — including some pump.fun graduates, most LaunchLab pools, and Meteora curve tokens. Here's what changed, and why rent recovery tools need to handle both.

Two programs, two program IDs

Solana identifies which token standard an account belongs to by its program ID:

Standard Program ID
Legacy SPL Token TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
Token-2022 TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb

Both programs implement the same basic interface (mint, transfer, close, etc.) with the same opcodes. If a tool only checks legacy Token accounts, it misses every Token-2022 account you own.

What Token-2022 adds

Token-2022 is fully backward compatible for the basic operations but adds a set of extensions that can be enabled per mint or per account:

Not every Token-2022 token uses all these extensions. Most just use the base functionality.

Why LaunchLab and pump.fun use Token-2022

Two main reasons:

  1. Transfer fees: LaunchLab tokens often include a small trading fee that gets redistributed to holders (loyalty/farming mechanics). This requires the transfer fee extension.

  2. Metadata pointer: cheaper to have metadata inline in the mint rather than via a separate Metaplex account. Saves rent overall.

Pump.fun still primarily uses legacy Token for pre-graduation tokens, but the migration path to Raydium after graduation can involve Token-2022 wrappers depending on the pool type.

Rent-exempt deposit — same math, both programs

The rent-exempt minimum for both a legacy Token account and a Token-2022 base account is 0.00203928 SOL for the standard 165-byte data length.

Token-2022 accounts that use extensions are larger:

Extensions Account size Rent minimum
None (base) 165 bytes 0.00203928 SOL
Transfer fees 214 bytes 0.00237456 SOL
Interest bearing 173 bytes 0.00209496 SOL
Both 222 bytes 0.00242920 SOL

When SolDuster closes a Token-2022 account with extensions, it recovers the full extended deposit (0.0024+ SOL), not just the base 0.00204.

Closing accounts: the instruction is the same

Both programs implement closeAccount at the same opcode:

// Token program instruction discriminator for closeAccount = 9
[9]

Accounts required: 1. Account to close (writable) 2. Destination for reclaimed rent (writable) — usually your main wallet 3. Owner (signer) — cryptographically must sign

The only difference: when calling closeAccount, the transaction must reference the correct program ID. If you send a Token-2022 close instruction to the legacy Token program, or vice versa, the transaction fails.

Tool implementation looks like this in @solana/web3.js:

import {
  TOKEN_PROGRAM_ID,        // legacy
  TOKEN_2022_PROGRAM_ID,   // new
  createCloseAccountInstruction
} from '@solana/spl-token';

// Determine which program the account belongs to
const accountInfo = await connection.getAccountInfo(ataAddress);
const programId = accountInfo.owner;

// Build the close instruction with the correct program ID
const ix = createCloseAccountInstruction(
  ataAddress,
  walletAddress,   // rent destination
  walletAddress,   // authority
  [],
  programId        // this is what routes the call correctly
);

Detecting both when scanning a wallet

The naive approach — calling getTokenAccountsByOwner with only TOKEN_PROGRAM_ID — misses every Token-2022 account. You need two calls:

const legacy = await connection.getTokenAccountsByOwner(
  wallet,
  { programId: TOKEN_PROGRAM_ID }
);

const token2022 = await connection.getTokenAccountsByOwner(
  wallet,
  { programId: TOKEN_2022_PROGRAM_ID }
);

const allAccounts = [...legacy.value, ...token2022.value];

For a wallet with 400 SPL tokens, this doubles your RPC load. Public api.mainnet-beta.solana.com will rate-limit you if you do it often. Recovery tools typically pool multiple RPC endpoints (paid + free-tier) to avoid this.

What if I only use legacy tools?

You'll still recover SOL — just not all of it. Legacy-only tools miss Token-2022 accounts entirely. If you've traded any LaunchLab tokens, most Meteora curves, or newer pump.fun launches, you have Token-2022 accounts that need a Token-2022-aware tool.

SolDuster, jup.ag/close (recent versions), and modern updates to sol-incinerator all handle both. The Solana CLI's spl-token command handles both if you specify --program-2022 explicitly for those accounts.

Programmatic detection

If you want to check yourself which program a given ATA belongs to, use Solscan:

https://solscan.io/account/YOUR_ATA_ADDRESS

The "Program" field shows either TokenkegQfe... (legacy) or TokenzQdBNbL... (Token-2022).

Or use solana account:

solana account <ATA_ADDRESS> --output json | jq '.account.owner'

Bottom line

If you're only closing legacy-token empty accounts, you're leaving SOL on the table. Any modern rent-recovery tool should scan both. Verify by checking your total scan count in the tool's UI — if it looks low relative to how many tokens you've held, the tool might be legacy-only.

SolDuster explicitly scans both program IDs in every check. See the live counters or check your own wallet for a full recoverable estimate.


Follow @SoldusterHQ for updates on Solana rent mechanics and recovery tooling.


Scan your wallet on solduster.com →