> ## Documentation Index
> Fetch the complete documentation index at: https://www.zkcompression.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Merge Compressed Token Accounts

> Consolidate multiple compressed token accounts of the same mint into a single account to reduce fragmentation.

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 interface PDA for compression
      owner,
  );
  ```
</CodeGroup>

## Get Started

<Steps>
  <Step>
    ### Merge Compressed Accounts

    <Accordion title="Installation">
      <Tabs>
        <Tab title="npm">
          Install packages in your working directory:

          ```bash theme={null}
          npm install @lightprotocol/stateless.js@^0.23.0 \
                      @lightprotocol/compressed-token@^0.23.0
          ```

          Install the CLI globally:

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

        <Tab title="yarn">
          Install packages in your working directory:

          ```bash theme={null}
          yarn add @lightprotocol/stateless.js@^0.23.0 \
                   @lightprotocol/compressed-token@^0.23.0
          ```

          Install the CLI globally:

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

        <Tab title="pnpm">
          Install packages in your working directory:

          ```bash theme={null}
          pnpm add @lightprotocol/stateless.js@^0.23.0 \
                   @lightprotocol/compressed-token@^0.23.0
          ```

          Install the CLI globally:

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

        <Tab title="SDK 2.0 (token-interface)">
          Install packages in your working directory:

          ```bash theme={null}
          # npm
          npm install @lightprotocol/stateless.js@^0.23.0 \
                      @lightprotocol/token-interface@^0.1.2

          # yarn
          yarn add @lightprotocol/stateless.js@^0.23.0 \
                   @lightprotocol/token-interface@^0.1.2

          # pnpm
          pnpm add @lightprotocol/stateless.js@^0.23.0 \
                   @lightprotocol/token-interface@^0.1.2
          ```

          Install the CLI globally:

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

    <Tabs>
      <Tab title="Localnet">
        ```bash theme={null}
        # start local test-validator in a separate terminal
        light test-validator
        ```

        <Note>
          In the code examples, use `createRpc()` without arguments for localnet.
        </Note>
      </Tab>

      <Tab title="Devnet">
        Get an API key from [Helius](https://helius.dev) and add to `.env`:

        ```bash title=".env" theme={null}
        API_KEY=<your-helius-api-key>
        ```

        <Note>
          In the code examples, use `createRpc(RPC_URL)` with the devnet URL.
        </Note>
      </Tab>
    </Tabs>

    ```typescript theme={null}
    import "dotenv/config";
    import { Keypair } from "@solana/web3.js";
    import { createRpc, bn } from "@lightprotocol/stateless.js";
    import { createMint, mintTo, mergeTokenAccounts } from "@lightprotocol/compressed-token";
    import { homedir } from "os";
    import { readFileSync } from "fs";

    // devnet:
    const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`;
    // localnet:
    // const RPC_URL = undefined;
    const payer = Keypair.fromSecretKey(
        new Uint8Array(
            JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8"))
        )
    );

    (async function () {
        // devnet:
        const rpc = createRpc(RPC_URL);
        // localnet:
        // const rpc = createRpc();

        // Setup: Create mint and mint multiple times to create multiple accounts
        const { mint } = await createMint(rpc, payer, payer.publicKey, 9);
        const owner = Keypair.generate();
        await mintTo(rpc, payer, mint, owner.publicKey, payer, bn(100_000_000));
        await mintTo(rpc, payer, mint, owner.publicKey, payer, bn(200_000_000));
        await mintTo(rpc, payer, mint, owner.publicKey, payer, bn(300_000_000));

        // Merge all accounts for owner
        const tx = await mergeTokenAccounts(rpc, payer, mint, owner);

        console.log("Mint:", mint.toBase58());
        console.log("Tx:", tx);
    })();
    ```

    <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/create-mint-with-token-pool) or added to existing SPL mints via [`createTokenPool()`](/compressed-tokens/guides/add-token-pools-to-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="How to Approve and Revoke Delegate Authority" icon="chevron-right" color="#0066ff" href="/compressed-tokens/guides/delegate" horizontal />
