compress() and decompress() functions convert SPL tokens between compressed and regular format.
Report incorrect code
Copy
Ask AI
// 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)
);
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.
Full Code Example
1
Prerequisites
Make sure you have dependencies and developer environment set up!Prerequisites & Setup
Prerequisites & Setup
DependenciesDeveloper Environment
- npm
- yarn
- pnpm
Report incorrect code
Copy
Ask AI
npm install @lightprotocol/stateless.js@alpha \
@lightprotocol/compressed-token@alpha
Report incorrect code
Copy
Ask AI
yarn add @lightprotocol/stateless.js@alpha \
@lightprotocol/compressed-token@alpha
Report incorrect code
Copy
Ask AI
pnpm add @lightprotocol/stateless.js@alpha \
@lightprotocol/compressed-token@alpha
- Localnet
- Devnet
By default, all guides use Localnet.
- npm
- yarn
- pnpm
Report incorrect code
Copy
Ask AI
npm install -g @lightprotocol/zk-compression-cli@alpha
Report incorrect code
Copy
Ask AI
yarn global add @lightprotocol/zk-compression-cli@alpha
Report incorrect code
Copy
Ask AI
pnpm add -g @lightprotocol/zk-compression-cli@alpha
Report incorrect code
Copy
Ask AI
# Start a local test validator
light test-validator
## ensure you have the Solana CLI accessible in your system PATH
Report incorrect code
Copy
Ask AI
// createRpc() defaults to local test validator endpoints
import {
Rpc,
createRpc,
} from "@lightprotocol/stateless.js";
const connection: Rpc = createRpc();
async function main() {
let slot = await connection.getSlot();
console.log(slot);
let health = await connection.getIndexerHealth(slot);
console.log(health);
// "Ok"
}
main();
Replace
<your-api-key> with your actual API key. Get your API key here, if you don’t have one yet.Report incorrect code
Copy
Ask AI
import { createRpc } from "@lightprotocol/stateless.js";
// Helius exposes Solana and Photon RPC endpoints through a single URL
const RPC_ENDPOINT = "https://devnet.helius-rpc.com?api-key=<your_api_key>";
const connection = createRpc(RPC_ENDPOINT, RPC_ENDPOINT, RPC_ENDPOINT);
console.log("Connection created!");
console.log("RPC Endpoint:", RPC_ENDPOINT);
2
Compress / Decompress Tokens
Run this script to compress / decompress tokens!Before we can compress or decompresss, we need:
- An SPL mint with a token pool for compression. This token pool can be created for new SPL mints via
createMint()or added to existing SPL mints viacreateTokenPool(). - For
compress()SPL tokens in an Associated Token Account, or - For
decompress()compressed token accounts with sufficient balance.
- Compress Tokens
- Compress and Decompress
compress-tokens.ts
Report incorrect code
Copy
Ask AI
// 1. Setup funded payer and connect to local validator
// 2. Create SPL mint with token pool and mint SPL tokens to ATA
// 3. Call compress() to convert SPL tokens to compressed format
// 4. Verify balances via getTokenAccountBalance and getCompressedTokenAccountsByOwner
import { Keypair } from '@solana/web3.js';
import { createRpc } from '@lightprotocol/stateless.js';
import {
createMint,
compress
} from '@lightprotocol/compressed-token';
import {
getOrCreateAssociatedTokenAccount,
mintTo as splMintTo,
TOKEN_PROGRAM_ID
} from '@solana/spl-token';
import BN from 'bn.js';
async function compressTokens() {
// 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 SPL tokens to ATA
const { mint } = await createMint(rpc, payer, payer.publicKey, 9);
console.log("Mint with token pool created:", mint.toBase58());
const tokenOwner = Keypair.generate();
const tokenAccount = await getOrCreateAssociatedTokenAccount(
rpc, payer, mint, tokenOwner.publicKey, false, TOKEN_PROGRAM_ID
);
// Mint SPL tokens to the ATA
const splAmount = 1_000_000_000; // 1 token with 9 decimals
await splMintTo(rpc, payer, mint, tokenAccount.address, payer, splAmount, [], undefined, TOKEN_PROGRAM_ID);
console.log("SPL tokens minted:", splAmount / 1_000_000_000, "tokens");
console.log("Compress Tokens");
const compressAmount = 400_000_000; // 0.4 tokens
// Step 3: 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.address, // source token account
tokenOwner.publicKey, // recipient for compressed tokens
);
console.log("Compressed amount:", compressAmount / 1_000_000_000, "tokens");
console.log("Transaction:", compressTx);
// Step 4: Verify balances via getTokenAccountBalance and getCompressedTokenAccountsByOwner
const finalTokenBalance = await rpc.getTokenAccountBalance(tokenAccount.address);
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);
Compress SPL tokens and decompress in one script.
compress-and-decompress-tokens.ts
Report incorrect code
Copy
Ask AI
// 1. Setup funded payer and connect to local validator
// 2. Create SPL mint with token pool and mint SPL tokens to ATA
// 3. Compress SPL tokens to compressed format
// 4. Decompress compressed tokens back to SPL format
// 5. Verify final balances
import { Keypair } from '@solana/web3.js';
import { createRpc } from '@lightprotocol/stateless.js';
import {
createMint,
compress,
decompress
} from '@lightprotocol/compressed-token';
import {
getOrCreateAssociatedTokenAccount,
mintTo as splMintTo,
TOKEN_PROGRAM_ID
} from '@solana/spl-token';
import BN from 'bn.js';
async function compressAndDecompressTokens() {
// 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 SPL tokens to ATA
const { mint } = await createMint(rpc, payer, payer.publicKey, 9);
console.log("Mint with token pool created:", mint.toBase58());
const tokenOwner = Keypair.generate();
const tokenAccount = await getOrCreateAssociatedTokenAccount(
rpc, payer, mint, tokenOwner.publicKey, false, TOKEN_PROGRAM_ID
);
// Mint SPL tokens to the ATA
const splAmount = 1_000_000_000; // 1 token with 9 decimals
await splMintTo(rpc, payer, mint, tokenAccount.address, payer, splAmount, [], undefined, TOKEN_PROGRAM_ID);
console.log("SPL tokens minted:", splAmount / 1_000_000_000, "tokens");
console.log("\n=== Compress Tokens ===");
const compressAmount = 600_000_000; // 0.6 tokens
// Step 3: Compress SPL tokens
const compressTx = await compress(
rpc,
payer,
mint,
compressAmount,
tokenOwner,
tokenAccount.address,
tokenOwner.publicKey,
);
console.log("Compressed amount:", compressAmount / 1_000_000_000, "tokens");
console.log("Compress transaction:", compressTx);
// Verify compressed balance
const compressedAccounts = await rpc.getCompressedTokenAccountsByOwner(
tokenOwner.publicKey,
{ mint }
);
const compressedBalance = compressedAccounts.items.reduce(
(sum, account) => sum.add(account.parsed.amount),
new BN(0)
);
console.log("Compressed balance:", compressedBalance.toNumber() / 1_000_000_000, "tokens");
console.log("\n=== Decompress Tokens ===");
const decompressAmount = 300_000_000; // 0.3 tokens
// Step 4: Decompress compressed tokens back to SPL format
const decompressTx = await decompress(
rpc,
payer,
mint,
decompressAmount,
tokenOwner,
tokenAccount.address,
);
console.log("Decompressed amount:", decompressAmount / 1_000_000_000, "tokens");
console.log("Decompress transaction:", decompressTx);
// Step 5: Verify final balances
const finalTokenBalance = await rpc.getTokenAccountBalance(tokenAccount.address);
const finalCompressedAccounts = await rpc.getCompressedTokenAccountsByOwner(
tokenOwner.publicKey,
{ mint }
);
const finalCompressedBalance = finalCompressedAccounts.items.reduce(
(sum, account) => sum.add(account.parsed.amount),
new BN(0)
);
console.log("\n=== Final Balances ===");
console.log("Regular SPL tokens:", finalTokenBalance.value.uiAmount);
console.log("Compressed tokens:", finalCompressedBalance.toNumber() / 1_000_000_000);
return {
compressTransaction: compressTx,
decompressTransaction: decompressTx,
finalCompressedBalance,
finalSplBalance: finalTokenBalance.value.amount
};
}
compressAndDecompressTokens().catch(console.error);
Make sure the SPL mint has a token pool for compression.
The script creates this token pool for you.For development, you can create a new mint with token pool via
The script creates this token pool for you.For development, you can create a new mint with token pool via
createMint() or add a token pool to an existing mint via createTokenPool().Troubleshooting
Insufficient balance between decompress and compress
Insufficient balance between decompress and compress
Check your balances before operations:
Report incorrect code
Copy
Ask AI
// For decompression - check compressed balance
const compressedAccounts = await rpc.getCompressedTokenAccountsByOwner(
owner.publicKey,
{ mint }
);
const compressedBalance = compressedAccounts.items.reduce(
(sum, account) => sum.add(account.parsed.amount),
new BN(0)
);
// For compression - check SPL token balance
const tokenBalance = await rpc.getTokenAccountBalance(tokenAccount);
const splBalance = new BN(tokenBalance.value.amount);
console.log("Can decompress up to:", compressedBalance.toString());
console.log("Can compress up to:", splBalance.toString());
Invalid owner
Invalid owner
Ensure the signer owns the tokens being decompressed/compressed:
Report incorrect code
Copy
Ask AI
// The owner parameter must be the actual owner
const decompressTx = await decompress(
rpc,
payer, // can be different (pays fees)
mint,
amount,
actualOwner, // must own compressed tokens
destinationAta,
);
const compressTx = await compress(
rpc,
payer, // can be different (pays fees)
mint,
amount,
actualOwner, // must own SPL tokens
sourceAta,
recipient,
);
Advanced Configuration
Compress to Different Owner
Compress to Different Owner
Compress tokens directly to someone else:
Report incorrect code
Copy
Ask AI
const recipientWallet = new PublicKey("RECIPIENT_WALLET_ADDRESS");
// Compress your SPL tokens to recipient
const compressTx = await compress(
rpc,
payer,
mint,
amount,
tokenOwner, // current owner signs
tokenAccount, // your token account
recipientWallet, // recipient gets compressed tokens
);
Batch Operations
Batch Operations
Compress multiple token accounts:
Report incorrect code
Copy
Ask AI
// Compress to multiple recipients at once
const recipients = [recipient1.publicKey, recipient2.publicKey, recipient3.publicKey];
const amounts = [1_000_000_000, 2_000_000_000, 500_000_000]; // Different amounts
const batchCompressTx = await compress(
rpc,
payer,
mint,
amounts, // Array of amounts
owner,
tokenAccount,
recipients, // Array of recipients
);
console.log("Batch compression completed:", batchCompressTx);
Decompress with Delegate Authority
Decompress with Delegate Authority
Decompress tokens using delegate authority:
Report incorrect code
Copy
Ask AI
import { decompressDelegated } from '@lightprotocol/compressed-token';
import { getAssociatedTokenAddress, TOKEN_PROGRAM_ID } from '@solana/spl-token';
// Get ATA for decompressed tokens
const ataAddress = await getAssociatedTokenAddress(
mint,
recipient,
false,
TOKEN_PROGRAM_ID
);
// Delegate decompresses tokens
await decompressDelegated(
rpc,
payer,
mint,
amount,
delegate, // Signer - owner of compressed tokens
ataAddress, // Uncompressed token account (ATA)
);