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

# Transfer Compressed Tokens

> Guide to transfer compressed SPL tokens between compressed or regular accounts with `transfer()`, troubleshooting and advanced configurations.

The `transfer()` function moves compressed tokens between accounts.

* SPL token transfers that update the existing account
* Compressed token transfers consume input accounts from the sender and create new output accounts for sender and recipient with updated balances.

<Tip>
  SPL token accounts can be compressed in the same transaction with `compress_or_decompress_amount`, if needed.
</Tip>

```typescript function-transfer-compressed-tokens.ts theme={null}
// Transfer compressed tokens
const transactionSignature = await transfer(
    rpc,
    payer,
    mint, // SPL mint with token pool for compression
    amount,
    payer,
    recipient, // destination address (toAddress parameter)
)
```

# 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>
    ### Transfer Compressed Tokens

    Run this script to transfer compressed tokens to a recipient!

    ```typescript transfer-compressed-tokens.ts highlight={49-57} expandable theme={null}
    // 1. Setup funded payer and connect to local validator
    // 2. Create SPL mint and token pool for compression with initial tokens
    // 3. Call transfer() with mint, amount, owner, recipient
    // 4. Verify transferred tokens via getCompressedTokenAccountsByOwner

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

    async function transferCompressedTokens() {
        // 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 2a: Create SPL mint with token pool for compression
        const { mint, transactionSignature: mintCreateTx } = await createMint(
            rpc,
            payer,
            payer.publicKey, // mint authority
            9
        );

        console.log("SPL mint with token pool for compression created");
        console.log("Mint address:", mint.toBase58());
        console.log("Create mint transaction:", mintCreateTx);

        // Step 2b: Create token owner and mint initial tokens
        const tokenOwner = Keypair.generate();
        const initialMintAmount = 1_000_000_000; // 1 token with 9 decimals

        const mintToTx = await mintTo(
            rpc,
            payer,
            mint, // SPL mint with token pool for compression
            tokenOwner.publicKey, // recipient
            payer, // mint authority
            initialMintAmount
        );

        console.log("\nCompressed Tokens minted:", initialMintAmount / 1_000_000_000, "tokens");
        console.log("Mint tokens transaction:", mintToTx);

        // Generate recipient address and define transfer amount
        const recipient = Keypair.generate();
        const transferAmount = 500_000_000; // 0.5 tokens

        // Step 3: Call transfer() with mint, amount, owner, recipient
        const transferTx = await transfer(
            rpc,
            payer,
            mint, // SPL mint with token pool for compression
            transferAmount,
            tokenOwner, // owner keypair
            recipient.publicKey // recipient address
        );

        console.log("\nCompressed tokens transferred!");
        console.log("From:", tokenOwner.publicKey.toBase58());
        console.log("To:", recipient.publicKey.toBase58());
        console.log("Amount transferred:", transferAmount / 1_000_000_000, "tokens");
        console.log("Transfer transaction:", transferTx);

        // Step 4: Verify transferred tokens via getCompressedTokenAccountsByOwner
        const recipientAccounts = await rpc.getCompressedTokenAccountsByOwner(
            recipient.publicKey,
            { mint }
        );

        // Check recipient received the tokens
        if (recipientAccounts.items.length > 0) {
            const receivedBalance = recipientAccounts.items[0].parsed.amount;
        }

        return {
            transferTransaction: transferTx,
            recipient: recipient.publicKey,
            amount: transferAmount
        };
    }

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

    <Info>
      Make sure the SPL mint has a token pool for compression.<br /> The script creates this token pool for you.

      For development, you can create a new mint with token pool via [`createMint()`](/compressed-tokens/guides/how-to-create-and-register-a-mint-account-for-compression) or add a token pool to an existing mint via [`createTokenPool()`](/compressed-tokens/guides/how-to-create-compressed-token-pools-for-mint-accounts).
    </Info>
  </Step>
</Steps>

# Troubleshooting

<AccordionGroup>
  <Accordion title="Insufficient balance for transfer">
    The sender doesn't have enough compressed tokens for the requested transfer amount.

    ```typescript theme={null}
    // Check current balance first
    const tokenAccounts = await rpc.getCompressedTokenAccountsByOwner(
        owner.publicKey,
        { mint }
    );

    if (tokenAccounts.items.length === 0) {
        throw new Error("No compressed token accounts found");
    }

    // Calculate total balance across all accounts
    const totalBalance = tokenAccounts.items.reduce(
        (sum, account) => sum.add(account.parsed.amount),
        new BN(0)
    );

    console.log("Available balance:", totalBalance.toString());

    // Ensure transfer amount doesn't exceed balance
    if (new BN(transferAmount).gt(totalBalance)) {
        throw new Error(`Transfer amount ${transferAmount} exceeds balance ${totalBalance.toString()}`);
    }
    ```
  </Accordion>

  <Accordion title="Account limit exceeded">
    The transfer requires more than 4 compressed accounts, which exceeds the transaction limit.

    ```typescript theme={null}
    // Error message: "Account limit exceeded: max X (4 accounts) per transaction.
    // Total balance: Y (Z accounts). Consider multiple transfers to spend full balance."

    // Split into multiple smaller transfers
    const maxTransferPerTx = 1_000_000_000; // Adjust based on your account sizes

    if (transferAmount > maxTransferPerTx) {
        console.log("Large transfer detected, splitting into multiple transactions...");

        let remainingAmount = transferAmount;
        while (remainingAmount > 0) {
            const currentTransfer = Math.min(remainingAmount, maxTransferPerTx);

            await transfer(
                rpc,
                payer,
                mint,
                currentTransfer,
                owner,
                recipient
            );

            remainingAmount -= currentTransfer;
            console.log(`Transferred ${currentTransfer}, remaining: ${remainingAmount}`);
        }
    }
    ```
  </Accordion>
</AccordionGroup>

# Advanced Configuration

<AccordionGroup>
  <Accordion title="Transfer to Multiple Recipients">
    Transfer to multiple recipients in separate transactions:

    ```typescript theme={null}
    const recipients = [
        Keypair.generate().publicKey,
        Keypair.generate().publicKey,
        Keypair.generate().publicKey,
    ];

    const amounts = [
        100_000_000, // 0.1 tokens
        200_000_000, // 0.2 tokens
        150_000_000, // 0.15 tokens
    ];

    for (let i = 0; i < recipients.length; i++) {
        const transactionSignature = await transfer(
            rpc,
            payer,
            mint,
            amounts[i],
            owner,
            recipients[i],
        );

        console.log(`Transfer ${i + 1} completed:`, transactionSignature);
    }
    ```
  </Accordion>

  <Accordion title="Transfer with Delegate Authority">
    Transfer tokens using delegate authority:

    ```typescript theme={null}
    import { approve, transferDelegated } from '@lightprotocol/compressed-token';

    // 1. Owner approves delegate
    await approve(
        rpc,
        payer,
        mint,
        amount,
        owner, // Signer
        delegate.publicKey, // PublicKey
    );

    // 2. Delegate transfers tokens
    await transferDelegated(
        rpc,
        payer,
        mint,
        transferAmount,
        delegate, // Signer - named "owner" in SDK
        recipient,
    );
    ```
  </Accordion>
</AccordionGroup>

# Next Steps

<Card title="Learn how to compress and decompress SPL tokens." icon="chevron-right" color="#0066ff" href="/compressed-tokens/guides/how-to-compress-and-decompress-spl-tokens" horizontal />
