Skip to main content
The approve() and revoke() functions grant and remove delegate spending authority for compressed tokens. Only the token owner can perform these instructions.
// 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
);

Full Code Example

1

Prerequisites

Make sure you have dependencies and developer environment set up!
Dependencies
npm install @lightprotocol/stateless.js@alpha \
            @lightprotocol/compressed-token@alpha
Developer Environment
By default, all guides use Localnet.
npm install -g @lightprotocol/zk-compression-cli@alpha
# Start a local test validator
light test-validator

## ensure you have the Solana CLI accessible in your system PATH
// 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();
2

Approve / Revoke Delegates

Run these scripts to approve / revoke delegate authority!
Approve delegate authority for compressed tokens. The delegate can spend up to the approved amount.
approve-delegates.ts
// 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);
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() or added to existing SPL mints via createTokenPool().

Troubleshooting

Attempting to revoke non-delegated accounts.
/// 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;
}

Advanced Configuration

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);
}
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);
    }
}

Next Steps

Check out the advanced guides for airdrops, combining multiple instructions in one transaction, and client examples.