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

# Approve and Revoke Delegate Authority

> Grant and remove delegate spending authority for compressed tokens with approve() and revoke(). Only the token owner can perform these operations.

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 interface PDA 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>

## Get Started

<Steps>
  <Step>
    ### Approve / Revoke Delegates

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

    <Tabs>
      <Tab title="Approve">
        ```typescript theme={null}
        import "dotenv/config";
        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";
        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 tokens
            const { mint } = await createMint(rpc, payer, payer.publicKey, 9);
            const owner = Keypair.generate();
            await mintTo(rpc, payer, mint, owner.publicKey, payer, 1_000_000_000);

            // Approve delegate
            const delegate = Keypair.generate();
            const tx = await approve(rpc, payer, mint, new BN(500_000_000), owner, delegate.publicKey);

            console.log("Mint:", mint.toBase58());
            console.log("Delegate:", delegate.publicKey.toBase58());
            console.log("Tx:", tx);
        })();
        ```
      </Tab>

      <Tab title="Revoke">
        ```typescript theme={null}
        import "dotenv/config";
        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";
        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, mint tokens, and approve delegate
            const { mint } = await createMint(rpc, payer, payer.publicKey, 9);
            const owner = Keypair.generate();
            await mintTo(rpc, payer, mint, owner.publicKey, payer, 1_000_000_000);
            const delegate = Keypair.generate();
            await approve(rpc, payer, mint, new BN(500_000_000), owner, delegate.publicKey);

            // Get delegated accounts and revoke
            const delegatedAccounts = await rpc.getCompressedTokenAccountsByDelegate(delegate.publicKey, { mint });
            const tx = await revoke(rpc, payer, delegatedAccounts.items, owner);

            console.log("Mint:", mint.toBase58());
            console.log("Tx:", tx);
        })();
        ```
      </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/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="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="Combine multiple instructions in a single transaction" icon="chevron-right" color="#0066ff" href="/compressed-tokens/combine-instructions" horizontal />
