How to compress and decompress SPL Tokens
Complete guide to compress with `compress()` and decompress SPL Tokens with `decompress()`, troubleshooting and advanced configurations. Best used for transfers.
The compress()
and decompress()
functions convert SPL tokens between compressed and regular format.
The functions perform opposite operations:
compress()
locks SPL tokens in a token pool account and creates compressed accountsdecompress()
withdraws SPL tokens from the token pool to an Associated Token Account and invalidates compressed accounts
Before we convert formats, we need:
SPL mint registered with the compressed token program via
createMint()
orcreateTokenPool()
for
compress()
SPL tokens in an Associated Token AccountFor
decompress()
compressed token accounts with sufficient balance
Function Difference and Best Practice:
compress(amount, sourceTokenAccount, toAddress)
compresses specific amounts from source to a specified recipient. Use for transfers and precise amounts.compressSplTokenAccount(tokenAccount, remainingAmount)
compresses the entire SPL token account balance minus optional remaining amount only to the same owner. Use to migrate complete token accounts with optional partial retention. Here is how.
import { decompress, compress } from '@lightprotocol/compressed-token';
import { PublicKey } from '@solana/web3.js';
import { getOrCreateAssociatedTokenAccount } from '@solana/spl-token';
const mint = new PublicKey("YOUR_EXISTING_MINT_ADDRESS");
const recipient = new PublicKey("RECIPIENT_WALLET_ADDRESS");
const amount = 1_000_000_000; // 1 token (9 decimals)
// Create ATA for decompressed tokens
const tokenAccount = await getOrCreateAssociatedTokenAccount(
rpc, payer, mint, payer.publicKey
);
// Decompress compressed tokens to SPL tokens
const transactionSignature = await decompress(
rpc,
payer,
mint, // SPL mint with token pool for compression
amount,
payer, // owner of compressed tokens
tokenAccount.address, // destination token account (toAddress parameter)
);
// Compress SPL tokens to compressed tokens
const compressionSignature = await compress(
rpc,
payer,
mint, // SPL mint with token pool for compression
amount,
payer, // owner of SPL tokens
tokenAccount.address, // source SPL token account (sourceTokenAccount parameter)
recipient, // recipient owner address (toAddress parameter)
);
Full Code Example
Decompress Tokens
Convert compressed tokens to regular SPL tokens.
// 1. Setup funded payer and connect to local validator
// 2. Create SPL mint with token pool and mint initial compressed tokens
// 3. Call decompress() to convert compressed tokens to SPL tokens
// 4. Verify decompressed balance via getTokenAccountBalance
import { Keypair, PublicKey } from '@solana/web3.js';
import { createRpc } from '@lightprotocol/stateless.js';
import {
createMint,
mintTo,
decompress
} from '@lightprotocol/compressed-token';
import {
getOrCreateAssociatedTokenAccount,
TOKEN_PROGRAM_ID
} from '@solana/spl-token';
import * as fs from 'fs';
import * as os from 'os';
async function decompressTokens() {
// Step 1: Setup funded payer and connect to local validator
const rpc = createRpc(); // defaults to localhost:8899
const payer = Keypair.generate();
const airdropSignature = await rpc.requestAirdrop(payer.publicKey, 1000000000); // 1 SOL
await rpc.confirmTransaction(airdropSignature);
// Step 2: Create SPL mint with token pool and mint initial compressed tokens
const { mint } = await createMint(rpc, payer, payer.publicKey, 9);
console.log("Mint with token pool created:", mint.toBase58());
const tokenOwner = Keypair.generate();
const compressedAmount = 1_000_000_000; // 1 token with 9 decimals
await mintTo(rpc, payer, mint, tokenOwner.publicKey, payer, compressedAmount);
console.log("Compressed tokens minted:", compressedAmount / 1_000_000_000, "tokens");
// Create or get Associated Token Account for decompression
const tokenAccount = await getOrCreateAssociatedTokenAccount(
rpc, payer, mint, tokenOwner.publicKey, false, TOKEN_PROGRAM_ID
);
const decompressAmount = 500_000_000; // 0.5 tokens
console.log("Decompress Tokens");
// Step 3: Call decompress() to convert to SPL tokens
// Withdraw SPL tokens from omnibus pool and burn compressed tokens
const decompressTx = await decompress(
rpc,
payer,
mint, // SPL mint with token pool for compression
decompressAmount, // amount to decompress
tokenOwner, // owner of compressed tokens
tokenAccount.address, // destination token account (toAddress parameter)
);
console.log("Tokens decompressed:", decompressAmount / 1_000_000_000, "tokens");
console.log("Transaction:", decompressTx);
// Verify decompressed balance in SPL token account
const tokenBalance = await rpc.getTokenAccountBalance(tokenAccount.address);
console.log("SPL token balance:", tokenBalance.value.uiAmount);
// Save state for compress step
const state = {
mint: mint.toBase58(),
tokenOwner: Array.from(tokenOwner.secretKey),
tokenAccount: tokenAccount.address.toBase58(),
payer: Array.from(payer.secretKey)
};
fs.writeFileSync('./shared-state.json', JSON.stringify(state, null, 2));
return {
mint,
tokenOwner,
tokenAccount: tokenAccount.address,
decompressTransaction: decompressTx
};
}
decompressTokens().catch(console.error);
Compress Tokens
Continue from the previous step to compress regular SPL tokens back to compressed format.
// Continue from Step 1 - compress SPL tokens
// 1. Call compress() to convert SPL tokens to compressed format
// 2. Verify balances via getTokenAccountBalance and getCompressedTokenAccountsByOwner
import { Keypair, PublicKey } from '@solana/web3.js';
import { createRpc } from '@lightprotocol/stateless.js';
import { compress } from '@lightprotocol/compressed-token';
import {
mintTo as splMintTo,
TOKEN_PROGRAM_ID
} from '@solana/spl-token';
import BN from 'bn.js';
import * as fs from 'fs';
async function compressTokens() {
if (!fs.existsSync('./shared-state.json')) {
console.log("No SPL tokens found. Please run 'npx tsx decompress.ts first.");
return;
}
const state = JSON.parse(fs.readFileSync('./shared-state.json', 'utf8'));
const rpc = createRpc(); // defaults to localhost:8899
const payer = Keypair.fromSecretKey(new Uint8Array(state.payer));
const mint = new PublicKey(state.mint);
const tokenOwner = Keypair.fromSecretKey(new Uint8Array(state.tokenOwner));
const tokenAccount = new PublicKey(state.tokenAccount);
console.log("Compress Tokens");
// Add SPL tokens to account for compression
await splMintTo(rpc, payer, mint, tokenAccount, payer, 300_000_000, [], undefined, TOKEN_PROGRAM_ID);
const compressAmount = 400_000_000; // 0.4 tokens
// Step 1: Call compress() to convert to compressed format
// Lock SPL tokens to pool account and mint compressed tokens
const compressTx = await compress(
rpc,
payer,
mint, // SPL mint with token pool for compression
compressAmount, // amount to compress
tokenOwner, // owner of SPL tokens
tokenAccount, // source token account
tokenOwner.publicKey, // recipient for compressed tokens
);
console.log("Compressed amount:", compressAmount / 1_000_000_000, "tokens");
console.log("Transaction:", compressTx);
// Step 2: Verify balances via getTokenAccountBalance and getCompressedTokenAccountsByOwner
const finalTokenBalance = await rpc.getTokenAccountBalance(tokenAccount);
const finalCompressedAccounts = await rpc.getCompressedTokenAccountsByOwner(
tokenOwner.publicKey,
{ mint }
);
// Calculate total compressed balance
const finalCompressedBalance = finalCompressedAccounts.items.reduce(
(sum, account) => sum.add(account.parsed.amount),
new BN(0)
);
console.log("\nFinal balances:");
console.log("Regular SPL tokens:", finalTokenBalance.value.uiAmount);
console.log("Compressed tokens:", finalCompressedBalance.toNumber() / 1_000_000_000);
return {
compressTransaction: compressTx,
finalCompressedBalance,
finalSplBalance: finalTokenBalance.value.amount
};
}
compressTokens().catch(console.error);
Success!
You've decompressed and compressed tokens. The output shows:
Decompression: Compressed tokens converted to regular SPL tokens in your Associated Token Account
Compression: Regular SPL tokens converted to compressed tokens
Balance verification: Both operations confirmed with token amounts
Troubleshooting
Advanced Configurations
Next Steps
Learn how to compress complete token accounts in one transaction to reclaim rent.
How to Compress complete SPL Token AccountsLast updated