> ## Documentation Index
> Fetch the complete documentation index at: https://lightprotocol-migration.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.

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).

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

<CodeGroup>
  ````typescript function-merge-accounts.ts theme={null}
  ```typescript
  // 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

### Prerequisites

Make sure you have dependencies and developer environment set up!

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

  ```bash theme={null}
  npm install --save-dev typescript tsx @types/node && \
  npm install --save \
      @lightprotocol/stateless.js \
      @lightprotocol/compressed-token \
      @solana/web3.js \
      @solana/spl-token
  ```

  **Alternatives:**

  ```bash theme={null}
  yarn add --dev typescript tsx @types/node && \
  yarn add \
      @lightprotocol/stateless.js \
      @lightprotocol/compressed-token \
      @solana/web3.js \
      @solana/spl-token
  ```

  ```bash theme={null}
  pnpm add --save-dev typescript tsx @types/node && \
  pnpm add \
      @lightprotocol/stateless.js \
      @lightprotocol/compressed-token \
      @solana/web3.js \
      @solana/spl-token
  ```

  **Developer Environment**

  By default, this guide uses Localnet.

  ```bash theme={null}
  # Install the development CLI
  npm install @lightprotocol/zk-compression-cli
  ```

  ```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();
  ```

  **Alternative: Using Devnet**

  Follow these steps to develop create an RPC Connection. Replace `<your_api_key>` with your API key before running.

  <Info>
    [Get your API key here](https://www.helius.dev/zk-compression), if you don't have one yet.
  </Info>

  ```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);
  ```
</Accordion>

### 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);
```

### 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

Learn how to approve and revoke delegate authority for compressed token accounts.
