Decompress Compressed Tokens

Note:

You must use an RPC that supports Light Protocol such as Helius

import { bn, buildAndSignTx, sendAndConfirmTx, dedupeSigner, Rpc, createRpc } from "@lightprotocol/stateless.js";
import { ComputeBudgetProgram, Keypair, PublicKey } from "@solana/web3.js";
import { CompressedTokenProgram, getTokenPoolInfos, selectMinCompressedTokenAccountsForTransfer, selectTokenPoolInfosForDecompression, } from "@lightprotocol/compressed-token";
import { getOrCreateAssociatedTokenAccount } from "@solana/spl-token";
import bs58 from "bs58";
import dotenv from "dotenv";
dotenv.config();

// Set these values in your .env file
const RPC_ENDPOINT = process.env.RPC_ENDPOINT;
const mint = new PublicKey(process.env.MINT_ADDRESS!);
const payer = Keypair.fromSecretKey(bs58.decode(process.env.GET_PAYER_KEYPAIR!));

const owner = payer;
const amount = 1e5;
const connection: Rpc = createRpc(RPC_ENDPOINT);

(async () => {
    // 1. Create an associated token account for the user if it doesn't exist
    const ata = await getOrCreateAssociatedTokenAccount(
        connection,
        payer,
        mint,
        payer.publicKey
    );

    // 2. Fetch compressed token accounts
    const compressedTokenAccounts =
        await connection.getCompressedTokenAccountsByOwner(owner.publicKey, {
            mint,
        });
    console.log('compressedTokenAccounts', compressedTokenAccounts);

    // 3. Select
    const [inputAccounts] = selectMinCompressedTokenAccountsForTransfer(
        compressedTokenAccounts.items,
        bn(amount)
    );

    // 4. Fetch validity proof
    const proof = await connection.getValidityProof(
        inputAccounts.map((account) => account.compressedAccount.hash)
    );

    // 5. Fetch token pool infos
    const tokenPoolInfos = await getTokenPoolInfos(connection, mint);
    console.log('tokenPoolInfos', tokenPoolInfos);

    // 6. Select
    const selectedTokenPoolInfos = selectTokenPoolInfosForDecompression(
        tokenPoolInfos,
        amount
    );

    // 7. Build instruction
    const ix = await CompressedTokenProgram.decompress({
        payer: payer.publicKey,
        inputCompressedTokenAccounts: inputAccounts,
        toAddress: ata.address,
        amount,
        tokenPoolInfos: selectedTokenPoolInfos,
        recentInputStateRootIndices: proof.rootIndices,
        recentValidityProof: proof.compressedProof,
    });

    // 8. Sign, send, and confirm
    const { blockhash } = await connection.getLatestBlockhash();
    const additionalSigners = dedupeSigner(payer, [owner]);
    const signedTx = buildAndSignTx(
        [ComputeBudgetProgram.setComputeUnitLimit({ units: 300_000 }), ix],
        payer,
        blockhash,
        additionalSigners
    );
    return await sendAndConfirmTx(connection, signedTx);
})();