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

Get Started

1

Approve / Revoke Delegates

Install packages in your working directory:
npm install @lightprotocol/stateless.js@alpha \
            @lightprotocol/compressed-token@alpha
Install the CLI globally:
npm install -g @lightprotocol/zk-compression-cli@alpha
# start local test-validator in a separate terminal
light test-validator
In the code examples, use createRpc() without arguments for localnet.
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);
})();
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.