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

# Approve and Revoke Delegate Authority

> Complete guide to manage delegate authority for compressed tokens with `approve()` and `revoke()`, troubleshooting and advanced configurations.

The `approve()` and `revoke()` functions grant and remove delegate spending authority for compressed tokens. Only the token owner can perform these instructions.

<CodeGroup>
  ```typescript approve() theme={null}
  // Approve delegate for spending up to the specified amount
  const approveSignature = await approve(
      rpc,
      payer,
      mint, // SPL mint with token pool for compression
      amount,
      owner,
      delegate.publicKey, // delegate account
  );
  ```

  ```typescript revoke() theme={null}
  // Get delegated accounts for revocation
  const delegatedAccounts = await rpc.getCompressedTokenAccountsByDelegate(
      delegate.publicKey,
      { mint }
  );

  // Revoke delegate authority
  const revokeSignature = await revoke(
      rpc,
      payer,
      delegatedAccounts.items, // delegated compressed token accounts
      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>
    ### Approve / Revoke Delegates

    Run these scripts to approve / revoke delegate authority!

    <Tabs>
      <Tab title="Approve Delegate">
        Approve delegate authority for compressed tokens. The delegate can spend up to the approved amount.

        ```typescript approve-delegates.ts highlight={51-59, 65-69 } expandable lines theme={null}
        // 1. Setup funded payer and connect to local validator
        // 2. Create mint and token pool with initial tokens
        // 3. Call approve() with mint, amount, owner, delegate
        // 4. Verify delegation via getCompressedTokenAccountsByDelegate

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

        async function approveDelegates() {
            // 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 and mint initial tokens
            const { mint } = await createMint(
                rpc,
                payer,
                payer.publicKey, // mint authority
                9 // decimals
            );

            console.log("SPL mint with token pool created:", mint.toBase58());

            const tokenOwner = Keypair.generate();
            const initialAmount = 1_000_000_000; // 1 token with 9 decimals

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

            console.log("Initial tokens minted:", initialAmount / 1_000_000_000, "tokens");
            console.log("Token owner:", tokenOwner.publicKey.toBase58());

            // Generate delegate address and define amount to approve for delegation
            const delegate = Keypair.generate();
            const delegateAmount = 500_000_000; // 0.5 tokens

            // Step 3: Call approve() with mint, amount, owner, delegate
            const approveTx = await approve(
                rpc,
                payer,
                mint, // SPL mint with token pool for compression
                delegateAmount,
                tokenOwner, // owner keypair
                delegate.publicKey // delegate address
            );
            console.log("Delegate approved");
            console.log("Delegate:", delegate.publicKey.toBase58());
            console.log("Approved amount:", delegateAmount / 1_000_000_000, "tokens");
            console.log("Transaction:", approveTx);

            // Step 4: Verify delegation via getCompressedTokenAccountsByDelegate
            const delegateAccounts = await rpc.getCompressedTokenAccountsByDelegate(
                delegate.publicKey,
                { mint }
            );
            // Check delegated balance
            if (delegateAccounts.items.length > 0) {
                const delegatedBalance = delegateAccounts.items.reduce(
                    (sum, account) => sum.add(account.parsed.amount),
                    new BN(0)
                );
                console.log("Verified delegation:", delegatedBalance.toNumber() / 1_000_000_000, "tokens");
            }

            return {
                mint,
                tokenOwner,
                delegate: delegate.publicKey,
                approveTransaction: approveTx,
                delegatedAmount: delegateAmount
            };
        }

        approveDelegates().catch(console.error);
        ```
      </Tab>

      <Tab title="Approve and Revoke">
        Approve delegation, then revoke it in a single script.

        ```typescript approve-and-revoke-delegates.ts highlight={54-63, 69-73, 80-87, 91-95} expandable theme={null}
        // Complete workflow: approve and revoke delegation
        // 1. Setup and create mint with initial tokens
        // 2. Approve delegation
        // 3. Verify delegation exists
        // 4. Revoke delegation
        // 5. Verify delegation removed

        import { Keypair } from '@solana/web3.js';
        import { createRpc } from '@lightprotocol/stateless.js';
        import {
            createMint,
            mintTo,
            approve,
            revoke
        } from '@lightprotocol/compressed-token';
        import BN from 'bn.js';

        async function approveAndRevokeDelegates() {
            // 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);

            // Create SPL mint with token pool and mint initial tokens
            const { mint } = await createMint(
                rpc,
                payer,
                payer.publicKey, // mint authority
                9 // decimals
            );

            console.log("SPL mint with token pool created:", mint.toBase58());

            const tokenOwner = Keypair.generate();
            const initialAmount = 1_000_000_000; // 1 token with 9 decimals

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

            console.log("Initial tokens minted:", initialAmount / 1_000_000_000, "tokens");
            console.log("Token owner:", tokenOwner.publicKey.toBase58());

            // Generate delegate and define delegation amount
            const delegate = Keypair.generate();
            const delegateAmount = 500_000_000; // 0.5 tokens

            // Step 2: Approve delegation
            console.log("\n--- Approving Delegation ---");
            const approveTx = await approve(
                rpc,
                payer,
                mint,
                delegateAmount,
                tokenOwner,
                delegate.publicKey
            );
            console.log("Delegate approved");
            console.log("Delegate:", delegate.publicKey.toBase58());
            console.log("Approved amount:", delegateAmount / 1_000_000_000, "tokens");
            console.log("Transaction:", approveTx);

            // Step 3: Verify delegation exists
            const delegateAccountsBefore = await rpc.getCompressedTokenAccountsByDelegate(
                delegate.publicKey,
                { mint }
            );
            const delegatedBalance = delegateAccountsBefore.items.reduce(
                (sum, account) => sum.add(account.parsed.amount),
                new BN(0)
            );
            console.log("Verified delegation:", delegatedBalance.toNumber() / 1_000_000_000, "tokens");

            // Step 4: Revoke delegation
            console.log("\n--- Revoking Delegation ---");
            const revokeTx = await revoke(
                rpc,
                payer,
                delegateAccountsBefore.items, // delegated accounts to revoke
                tokenOwner,
            );
            console.log("Delegate revoked!");
            console.log("Transaction:", revokeTx);

                // Step 5: Verify delegation removed
            const delegateAccountsAfter = await rpc.getCompressedTokenAccountsByDelegate(
                delegate.publicKey,
                { mint }
            );
            const ownerAccounts = await rpc.getCompressedTokenAccountsByOwner(
                tokenOwner.publicKey,
                { mint }
            );
            const ownerBalance = ownerAccounts.items.reduce(
                (sum, account) => sum.add(account.parsed.amount),
                new BN(0)
            );

            console.log("\n--- Final State ---");
            console.log("Delegated accounts remaining:", delegateAccountsAfter.items.length);
            console.log("Owner balance after revocation:", ownerBalance.toNumber() / 1_000_000_000, "tokens");

            return {
                approveTransaction: approveTx,
                revokeTransaction: revokeTx,
                finalOwnerBalance: ownerBalance
            };
        }

        approveAndRevokeDelegates().catch(console.error);
        ```
      </Tab>
    </Tabs>

    <Info>
      Before we approve or revoke delegates, we need:

      * compressed token accounts to delegate or revoke delegation from, 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="Account is not delegated">
    Attempting to revoke non-delegated accounts.

    ```typescript theme={null}
    /// Verify accounts are delegated before revocation.
    const delegateAccounts = await rpc.getCompressedTokenAccountsByDelegate(
        delegate.publicKey,
        { mint }
    );

    if (delegateAccounts.items.length === 0) {
        console.log("No delegated accounts to revoke");
        return;
    }
    ```
  </Accordion>
</AccordionGroup>

# Advanced Configuration

<AccordionGroup>
  <Accordion title="Approve Multiple Delegates">
    ```typescript theme={null}
    const delegates = [
        Keypair.generate().publicKey,
        Keypair.generate().publicKey,
    ];

    const amounts = [
        200_000_000, // 0.2 tokens to first delegate
        300_000_000, // 0.3 tokens to second delegate
    ];

    // Approve each delegate
    for (let i = 0; i < delegates.length; i++) {
        const approveTx = await approve(
            rpc,
            payer,
            mint,
            amounts[i],
            tokenOwner,
            delegates[i],
        );

        console.log(`Delegate ${i + 1} approved:`, approveTx);
    }
    ```
  </Accordion>

  <Accordion title="Revoke Multiple Delegates">
    ```typescript theme={null}
    const delegates = [
        new PublicKey("DELEGATE_1_ADDRESS"),
        new PublicKey("DELEGATE_2_ADDRESS"),
    ];

    // Revoke each delegate
    for (const delegate of delegates) {
        // Get delegated accounts for this delegate
        const delegateAccounts = await rpc.getCompressedTokenAccountsByDelegate(
            delegate,
            { mint }
        );

        if (delegateAccounts.items.length > 0) {
            const revokeTx = await revoke(
                rpc,
                payer,
                delegateAccounts.items,
                tokenOwner,
            );

            console.log(`Delegate ${delegate.toBase58()} revoked:`, revokeTx);
        }
    }
    ```
  </Accordion>
</AccordionGroup>

# Next Steps

<Card title="Check out the advanced guides for airdrops, combining multiple instructions in one transaction, and client examples." icon="chevron-right" color="#0066ff" href="/compressed-tokens/advanced-guides" horizontal />
