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 interface PDA for compression
amount,
owner,
delegate.publicKey, // delegate account
);
// 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,
);
Get Started
Approve / Revoke Delegates
Installation
Installation
- npm
- yarn
- pnpm
- SDK 2.0 (token-interface)
Install packages in your working directory:Install the CLI globally:
npm install @lightprotocol/stateless.js@^0.23.0 \
@lightprotocol/compressed-token@^0.23.0
npm install -g @lightprotocol/zk-compression-cli
Install packages in your working directory:Install the CLI globally:
yarn add @lightprotocol/stateless.js@^0.23.0 \
@lightprotocol/compressed-token@^0.23.0
yarn global add @lightprotocol/zk-compression-cli
Install packages in your working directory:Install the CLI globally:
pnpm add @lightprotocol/stateless.js@^0.23.0 \
@lightprotocol/compressed-token@^0.23.0
pnpm add -g @lightprotocol/zk-compression-cli
Install packages in your working directory:Install the CLI globally:
# 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
npm install -g @lightprotocol/zk-compression-cli
- Localnet
- Devnet
# start local test-validator in a separate terminal
light test-validator
In the code examples, use
createRpc() without arguments for localnet.Get an API key from Helius and add to
.env:.env
API_KEY=<your-helius-api-key>
In the code examples, use
createRpc(RPC_URL) with the devnet URL.- Approve
- Revoke
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);
})();
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);
})();
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.
/// 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
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
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);
}
}