> ## Documentation Index
> Fetch the complete documentation index at: https://luminouslabs-cc5545c6-swen-add-code-runner.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Merge Compressed Token Accounts

> Complete guide to merge multiple compressed token accounts into a single account with mergeTokenAccounts(), troubleshooting and advanced configurations.

The `mergeTokenAccounts()` function consolidates multiple compressed accounts of the same mint into a single compressed account.

The function

1. consumes multiple compressed token accounts (up to 8 accounts), and
2. creates a single output compressed token account with combined balance for the owner.

<Tip>
  State trees where compressed account's are stored, are append only. `mergeTokenAccounts()` reduces account fragmentation to simplify balance calculations from `getCompressedTokenAccountsByOwner`.
</Tip>

<CodeGroup>
  ```typescript function-merge-accounts.ts theme={null}
  // Combines multiple compressed token accounts into single compressed account
  const transactionSignature = await mergeTokenAccounts(
      rpc,
      payer,
      mint, // SPL mint with token pool for compression
      owner,
  );
  ```
</CodeGroup>

# Full Code Example

<Steps>
  <Step>
    ### Prerequisites

    Make sure you have dependencies and developer environment set up!

    <Accordion title="Prerequisites & Setup">
      **Dependencies**

      <Tabs>
        <Tab title="npm">
          ```bash theme={null}
          npm install @lightprotocol/stateless.js@alpha \
                      @lightprotocol/compressed-token@alpha
          ```
        </Tab>

        <Tab title="yarn">
          ```bash theme={null}
          yarn add @lightprotocol/stateless.js@alpha \
                   @lightprotocol/compressed-token@alpha
          ```
        </Tab>

        <Tab title="pnpm">
          ```bash theme={null}
          pnpm add @lightprotocol/stateless.js@alpha \
                   @lightprotocol/compressed-token@alpha
          ```
        </Tab>
      </Tabs>

      **Developer Environment**

      <Tabs>
        <Tab title="Localnet">
          By default, all guides use Localnet.

          <Tabs>
            <Tab title="npm">
              ```bash theme={null}
              npm install -g @lightprotocol/zk-compression-cli@alpha
              ```
            </Tab>

            <Tab title="yarn">
              ```bash theme={null}
              yarn global add @lightprotocol/zk-compression-cli@alpha
              ```
            </Tab>

            <Tab title="pnpm">
              ```bash theme={null}
              pnpm add -g @lightprotocol/zk-compression-cli@alpha
              ```
            </Tab>
          </Tabs>

          ```bash theme={null}
          # Start a local test validator
          light test-validator

          ## ensure you have the Solana CLI accessible in your system PATH
          ```

          ```typescript theme={null}
          // 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();
          ```
        </Tab>

        <Tab title="Devnet">
          Replace `<your-api-key>` with your actual API key. [Get your API key here](https://www.helius.dev/zk-compression), if you don't have one yet.

          ```typescript theme={null}
          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);
          ```
        </Tab>
      </Tabs>
    </Accordion>
  </Step>

  <Step>
    ### Merging Compressed Accounts

    Run this script to merge multiple compressed token accounts into one!

    ```typescript merge-compressed-accounts.ts highlight={60-67} expandable theme={null}
    // 1: Setup funded payer and connect to local validator
    // 2. Create mint and multiple compressed accounts
    // 3. Call mergeTokenAccounts() to consolidate multiple compressed accounts to one output
    // 4. Use getCompressedTokenAccountsByOwner() to query account states before and after merge

    import { Keypair, PublicKey } from '@solana/web3.js';
    import { createRpc } from '@lightprotocol/stateless.js';
    import {
        createMint,
        mintTo,
        mergeTokenAccounts
    } from '@lightprotocol/compressed-token';

    async function mergeCompressedAccounts() {
        // 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 for compression
        const { mint } = await createMint(rpc, payer, payer.publicKey, 9);
        console.log("SPL Mint with token pool created:", mint.toBase58());

        const tokenOwner = Keypair.generate();
        const amounts = [300_000_000, 200_000_000, 500_000_000]; // 0.3, 0.2, 0.5 tokens

        console.log("Creating multiple compressed accounts...");

        for (let i = 0; i &#x3C; amounts.length; i++) {
            await mintTo(
                rpc,
                payer,
                mint, // SPL mint with token pool for compression
                tokenOwner.publicKey,// recipient address (toPubkey parameter)
                payer, // mint authority
                amounts[i],
            );
        }

        // Step 2a: Get all compressed accounts before merging
        const accountsBefore = await rpc.getCompressedTokenAccountsByOwner(
            tokenOwner.publicKey,
            { mint }
        );

        console.log("Number of accounts before merge:", accountsBefore.items.length);

        // Step 2b: Calculate total balance across all compressed accounts
        const totalBalance = accountsBefore.items.reduce(
            (sum, account) => sum.add(account.parsed.amount),
            new (require('bn.js'))(0)
        );
        console.log("Total balance:", totalBalance.toNumber() / 1_000_000_000, "tokens");

        accountsBefore.items.forEach((account, index) => {
            console.log(`Account ${index + 1}:`, account.parsed.amount.toNumber() / 1_000_000_000, "tokens");
        });

        // Step 3: Call mergeTokenAccounts() to consolidate into single account
        // Nullify old compressed accounts and create one with combined balance
        const mergeTx = await mergeTokenAccounts(
            rpc,
            payer,
            mint, // SPL mint with token pool for compression
            tokenOwner,
        );
        console.log("\nMerge Compressed Accounts...");
        console.log("Transaction:", mergeTx);

        // Step 4: Verify merge results - check single compressed account contains total balance
        const accountsAfter = await rpc.getCompressedTokenAccountsByOwner(
            tokenOwner.publicKey,
            { mint }
        );

        console.log("Number of accounts after merge:", accountsAfter.items.length);

        if (accountsAfter.items.length > 0) {
            const mergedBalance = accountsAfter.items[0].parsed.amount;
            console.log("Merged account balance:", mergedBalance.toNumber() / 1_000_000_000, "tokens");
        }


        return {
            mint,
            tokenOwner,
            mergeTransaction: mergeTx,
            accountsBefore: accountsBefore.items.length,
            accountsAfter: accountsAfter.items.length
        };

    }

    mergeCompressedAccounts().catch(console.error);
    ```

    <Info>
      Before we merge compressed accounts, we need

      * Multiple compressed token accounts of the same mint owned by the same wallet, and
      * an SPL mint with a token pool for compression. This token pool can be created for new SPL mints via [`createMint()`](/compressed-tokens/guides/how-to-create-and-register-a-mint-account-for-compression) or added to existing SPL mints via [`createTokenPool()`](/compressed-tokens/guides/how-to-create-compressed-token-pools-for-mint-accounts).
    </Info>
  </Step>
</Steps>

# Troubleshooting

<AccordionGroup>
  <Accordion title="No compressed token accounts found">
    The owner has no compressed token accounts for the specified mint:

    ```typescript theme={null}
    // Check if accounts exist before merging
    const accounts = await rpc.getCompressedTokenAccountsByOwner(
        owner.publicKey,
        { mint }
    );

    if (accounts.items.length === 0) {
        console.log("No compressed token accounts found for this mint");
        console.log("Mint address:", mint.toBase58());
        console.log("Owner address:", owner.publicKey.toBase58());
        return;
    }

    console.log(`Found ${accounts.items.length} accounts to merge`);
    ```
  </Accordion>
</AccordionGroup>

# Advanced Configuration

<AccordionGroup>
  <Accordion title="Conditional Merging">
    ```typescript theme={null}
    // Get account count
    const accounts = await rpc.getCompressedTokenAccountsByOwner(
        owner.publicKey,
        { mint }
    );

    // Only merge if more than 2 accounts
    if (accounts.items.length > 2) {
        console.log(`Merging ${accounts.items.length} accounts...`);

        const mergeTx = await mergeTokenAccounts(
            rpc,
            payer,
            mint,
            tokenOwner,
        );

        console.log("Merge completed:", mergeTx);
    } else {
        console.log("Merge not needed - optimal account structure");
    }
    ```
  </Accordion>

  <Accordion title="Merge Multiple Mints">
    ```typescript theme={null}
    const mints = [
        new PublicKey("MINT_1_ADDRESS"),
        new PublicKey("MINT_2_ADDRESS"),
    ];

    // Merge accounts for each mint
    for (const mint of mints) {
        console.log(`Merging accounts for mint: ${mint.toBase58()}`);

        const mergeTx = await mergeTokenAccounts(
            rpc,
            payer,
            mint,
            tokenOwner,
        );

        console.log(`Merge completed: ${mergeTx}`);
    }
    ```
  </Accordion>
</AccordionGroup>

# Next Steps

<Card title="Learn how to approve and revoke delegate authority for compressed token accounts." icon="chevron-right" color="#0066ff" href="/compressed-tokens/guides/how-to-approve-and-revoke-delegate-authority" horizontal />
