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

# Transfer Compressed Tokens

> Complete 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. Unlike regular SPL transfers that update existing account balances, compressed transfers consume input accounts from the sender and create new output accounts for sender and recipient with updated balances.

Before we can transfer compressed tokens, we need:

* 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)., and
* a source compressed token account with sufficient balance for the transfer amount.

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

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

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

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

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

Learn how compress and decompress SPL Tokens.
