approve() and revoke() functions grant and remove delegate spending authority for compressed tokens. Only the token owner can perform these instructions.
Report incorrect code
Copy
Ask AI
// 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!Prerequisites & Setup
Prerequisites & Setup
DependenciesDeveloper Environment
- npm
- yarn
- pnpm
Report incorrect code
Copy
Ask AI
npm install @lightprotocol/stateless.js@alpha \
@lightprotocol/compressed-token@alpha
Report incorrect code
Copy
Ask AI
yarn add @lightprotocol/stateless.js@alpha \
@lightprotocol/compressed-token@alpha
Report incorrect code
Copy
Ask AI
pnpm add @lightprotocol/stateless.js@alpha \
@lightprotocol/compressed-token@alpha
- Localnet
- Devnet
By default, all guides use Localnet.
- npm
- yarn
- pnpm
Report incorrect code
Copy
Ask AI
npm install -g @lightprotocol/zk-compression-cli@alpha
Report incorrect code
Copy
Ask AI
yarn global add @lightprotocol/zk-compression-cli@alpha
Report incorrect code
Copy
Ask AI
pnpm add -g @lightprotocol/zk-compression-cli@alpha
Report incorrect code
Copy
Ask AI
# Start a local test validator
light test-validator
## ensure you have the Solana CLI accessible in your system PATH
Report incorrect code
Copy
Ask AI
// 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();
Replace
<your-api-key> with your actual API key. Get your API key here, if you don’t have one yet.Report incorrect code
Copy
Ask AI
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);
2
Approve / Revoke Delegates
Run these scripts to approve / revoke delegate authority!- Approve Delegate
- Approve and Revoke
Approve delegate authority for compressed tokens. The delegate can spend up to the approved amount.
approve-delegates.ts
Report incorrect code
Copy
Ask AI
// 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);
Approve delegation, then revoke it in a single script.
approve-and-revoke-delegates.ts
Report incorrect code
Copy
Ask AI
// 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);
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 viacreateTokenPool().
Troubleshooting
Account is not delegated
Account is not delegated
Attempting to revoke non-delegated accounts.
Report incorrect code
Copy
Ask AI
/// 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
Approve Multiple Delegates
Approve Multiple Delegates
Report incorrect code
Copy
Ask AI
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);
}
Revoke Multiple Delegates
Revoke Multiple Delegates
Report incorrect code
Copy
Ask AI
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);
}
}