# Table of Contents - [Overview | ZK Compression](#overview-zk-compression) - [Intro to Development | ZK Compression](#intro-to-development-zk-compression) - [Event: 1000x Hackathon | ZK Compression](#event-1000x-hackathon-zk-compression) - [JS - v0.21.0 | ZK Compression](#js-v0-21-0-zk-compression) - [In a Nutshell | ZK Compression](#in-a-nutshell-zk-compression) - [Lifecycle of a Transaction | ZK Compression](#lifecycle-of-a-transaction-zk-compression) - [State Trees | ZK Compression](#state-trees-zk-compression) - [Validity Proofs | ZK Compression](#validity-proofs-zk-compression) - [Compressed Account Model | ZK Compression](#compressed-account-model-zk-compression) - [Core Concepts | ZK Compression](#core-concepts-zk-compression) - [TypeScript Client | ZK Compression](#typescript-client-zk-compression) - [Limitations | ZK Compression](#limitations-zk-compression) - [JSON RPC Methods | ZK Compression](#json-rpc-methods-zk-compression) - [getCompressedAccount | ZK Compression](#getcompressedaccount-zk-compression) - [getCompressedTokenAccountBalance | ZK Compression](#getcompressedtokenaccountbalance-zk-compression) - [getCompressedBalance | ZK Compression](#getcompressedbalance-zk-compression) - [getCompressedMintTokenHolders | ZK Compression](#getcompressedminttokenholders-zk-compression) - [getCompressedAccountsByOwner | ZK Compression](#getcompressedaccountsbyowner-zk-compression) - [getCompressedBalanceByOwner | ZK Compression](#getcompressedbalancebyowner-zk-compression) - [getMultipleCompressedAccountProofs | ZK Compression](#getmultiplecompressedaccountproofs-zk-compression) - [getCompressedTokenAccountsByOwner | ZK Compression](#getcompressedtokenaccountsbyowner-zk-compression) - [getCompressedTokenAccountsByDelegate | ZK Compression](#getcompressedtokenaccountsbydelegate-zk-compression) - [getCompressedAccountProof | ZK Compression](#getcompressedaccountproof-zk-compression) - [getCompressedTokenBalancesByOwnerV2 | ZK Compression](#getcompressedtokenbalancesbyownerv2-zk-compression) - [getCompressionSignaturesForTokenOwner | ZK Compression](#getcompressionsignaturesfortokenowner-zk-compression) - [getCompressionSignaturesForAccount | ZK Compression](#getcompressionsignaturesforaccount-zk-compression) - [Addresses and URLs | ZK Compression](#addresses-and-urls-zk-compression) - [getCompressionSignaturesForAddress | ZK Compression](#getcompressionsignaturesforaddress-zk-compression) - [getMultipleCompressedAccounts | ZK Compression](#getmultiplecompressedaccounts-zk-compression) - [getMultipleNewAddressProofs | ZK Compression](#getmultiplenewaddressproofs-zk-compression) - [getLatestCompressionSignatures | ZK Compression](#getlatestcompressionsignatures-zk-compression) - [getCompressionSignaturesForOwner | ZK Compression](#getcompressionsignaturesforowner-zk-compression) - [getTransactionWithCompressionInfo | ZK Compression](#gettransactionwithcompressioninfo-zk-compression) - [Using Token-2022 | ZK Compression](#using-token-2022-zk-compression) - [getIndexerHealth | ZK Compression](#getindexerhealth-zk-compression) - [getLatestNonVotingSignatures | ZK Compression](#getlatestnonvotingsignatures-zk-compression) - [getIndexerSlot | ZK Compression](#getindexerslot-zk-compression) - [getValidityProof | ZK Compression](#getvalidityproof-zk-compression) - [Create programs with the program-template | ZK Compression](#create-programs-with-the-program-template-zk-compression) - [Security | ZK Compression](#security-zk-compression) - [Add Compressed Token Support to Your Wallet | ZK Compression](#add-compressed-token-support-to-your-wallet-zk-compression) - [Run a Node | ZK Compression](#run-a-node-zk-compression) - [Privacy Policy | ZK Compression](#privacy-policy-zk-compression) - [Creating Airdrops with Compressed Tokens | ZK Compression](#creating-airdrops-with-compressed-tokens-zk-compression) - [Email Protection | Cloudflare](#email-protection-cloudflare) --- # Overview | ZK Compression [NextIntro to Development](https://www.zkcompression.com/introduction/intro-to-development) Last updated 1 month ago Was this helpful? [](https://www.zkcompression.com/#what-is-zk-compression) What is ZK Compression? -------------------------------------------------------------------------------------- ZK Compression is a new primitive on Solana that enables you to build applications at scale. Developers and users can compress their on-chain state, reducing data storage costs **by orders of magnitude** while preserving the Solana L1's security, performance, and composability. [](https://www.zkcompression.com/#state-cost-reduction) State Cost Reduction --------------------------------------------------------------------------------- Creation Cost Regular Account Compressed Account 100-byte PDA Account ~ 0.0016 SOL ~ 0.00001 SOL (160x cheaper) 100 Token Accounts ~ 0.2 SOL ~ 0.00004 SOL (5000x cheaper) [](https://www.zkcompression.com/#core-features) Core Features ------------------------------------------------------------------- **Minimal state cost** **L1 security & performance** Execution and data availability on Solana, preserving the performance and security guarantees of the L1 **Composable** Apps can mix and match between compressed and regular on-chain state, allowing atomic interaction with multiple programs, accounts, and compressed accounts. [](https://www.zkcompression.com/#zk-and-compression-in-a-nutshell) ZK and Compression in a Nutshell --------------------------------------------------------------------------------------------------------- [](https://www.zkcompression.com/#how-to-use-this-documentation) How to Use This Documentation --------------------------------------------------------------------------------------------------- This documentation introduces the ZK Compression primitive and guides you to relevant codebases and examples. Securely stores state on cheaper space instead of the more expensive account space, allowing apps to scale to millions of users. _**Compression**_**:** Only the (small fingerprints of all ) are stored in on-chain accounts. The underlying data is stored on the cheaper Solana ledger. _**ZK**_**:** The protocol uses small zero-knowledge proofs () to ensure the integrity of the compressed state. This is all done under the hood. You can fetch validity proofs from that support ZK Compression. ZK Compression is being built in the open, and Mainnet-Beta is live! Stay up to date with the core teams contributing to ZK Compression and its RPC implementation: and . [state roots](https://www.zkcompression.com/learn/core-concepts/state-trees) [compressed accounts](https://www.zkcompression.com/learn/core-concepts/compressed-account-model) [Light](https://twitter.com/LightProtocol) [Helius](https://twitter.com/heliuslabs) [ledger](https://solana.com/docs/terminology#ledger) [validity proofs](https://www.zkcompression.com/learn/core-concepts/validity-proofs) [RPC providers](https://www.zkcompression.com/introduction/intro-to-development#rpc-connection) ![](https://www.zkcompression.com/~gitbook/image?url=https%3A%2F%2F3488020389-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FDBJ4vLlhHTdkUGOiHxbB%252Fuploads%252FfthcsgsumQdVRYyvZOgH%252FBuild_Anything.png%3Falt%3Dmedia%26token%3D3f6c5bfc-a027-4228-bf50-f5773fa0feb4&width=768&dpr=4&quality=100&sign=5259984b&sv=2) --- # Intro to Development | ZK Compression [PreviousOverview](https://www.zkcompression.com/introduction/intro-to-development) [NextEvent: 1000x Hackathon](https://www.zkcompression.com/event/event-1000x-hackathon) Last updated 4 months ago Was this helpful? For the sake of brevity, this guide assumes you are familiar with the basics of Solana. If you aren't, we recommend reading the following: [](https://www.zkcompression.com/introduction/intro-to-development#what-youll-need-to-get-started) What You'll Need to Get Started --------------------------------------------------------------------------------------------------------------------------------------- Development with ZK Compression on Solana consists of two main parts: The is the glue between clients and on-chain programs. It extends Solana's with additional endpoints for interacting with ZK compressed accounts. You can view the complete list of supported endpoints . ### [](https://www.zkcompression.com/introduction/intro-to-development#a-quick-intro-to-client-side-development) A Quick Intro to Client-side Development The following TypeScript and Rust SDKs are used to interact with ZK Compression: Language SDK Description TypeScript SDK to interact with compression programs via the ZK Compression RPC API TypeScript SDK to interact with the compressed token program Rust Rust client #### [](https://www.zkcompression.com/introduction/intro-to-development#rpc-connection) RPC Connection You need an RPC connection to interact with the network. You can either work with an RPC infrastructure provider that supports ZK Compression or run your own RPC Node. supports ZK Compression and maintains its canonical RPC and . Our local dev tooling supports Photon out of the box via the `light test-validator` command. To learn how to run a standalone Photon RPC node, visit the section. ### [](https://www.zkcompression.com/introduction/intro-to-development#quickstart) Quickstart The code samples work! You can copy & paste them into your IDE and run! #### [](https://www.zkcompression.com/introduction/intro-to-development#installation-node.js-web) Installation (Node.js, Web) npm [](https://www.zkcompression.com/introduction/intro-to-development#tab-npm) yarn [](https://www.zkcompression.com/introduction/intro-to-development#tab-yarn) pnpm [](https://www.zkcompression.com/introduction/intro-to-development#tab-pnpm) Copy npm install -g @lightprotocol/zk-compression-cli && \ npm install --save \ @lightprotocol/stateless.js \ @lightprotocol/compressed-token \ @solana/web3.js Copy yarn global add @lightprotocol/zk-compression-cli && \ yarn add \ @lightprotocol/stateless.js \ @lightprotocol/compressed-token \ @solana/web3.js Copy pnpm add -g @lightprotocol/zk-compression-cli && \ pnpm add \ @lightprotocol/stateless.js \ @lightprotocol/compressed-token \ @solana/web3.js #### [](https://www.zkcompression.com/introduction/intro-to-development#creating-an-rpc-connection) Creating an RPC Connection Copy import { Rpc, 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="; const PHOTON_ENDPOINT = RPC_ENDPOINT; const PROVER_ENDPOINT = RPC_ENDPOINT; const connection: Rpc = createRpc(RPC_ENDPOINT, PHOTON_ENDPOINT, PROVER_ENDPOINT) console.log("connection", connection); #### [](https://www.zkcompression.com/introduction/intro-to-development#using-localnet) Using Localnet Copy # Start a local test validator light test-validator Copy const stateless = require("@lightprotocol/stateless.js"); const connection = stateless.createRpc(); async function main() { let slot = await connection.getSlot(); console.log(slot); let health = await connection.getIndexerHealth(slot); console.log(health); // "Ok" } main(); #### [](https://www.zkcompression.com/introduction/intro-to-development#minting-and-transferring-compressed-tokens) Minting and Transferring Compressed Tokens This example uses the **compressed token program**, which is built using ZK Compression and offers an SPL-compatible token layout. Copy import { LightSystemProgram, Rpc, confirmTx, createRpc, } from "@lightprotocol/stateless.js"; import { createMint, mintTo, transfer } from "@lightprotocol/compressed-token"; import { Keypair } from "@solana/web3.js"; const payer = Keypair.generate(); const tokenRecipient = Keypair.generate(); /// Helius exposes Solana and compression RPC endpoints through a single URL const RPC_ENDPOINT = "https://devnet.helius-rpc.com?api-key="; const COMPRESSION_ENDPOINT = RPC_ENDPOINT; const PROVER_ENDPOINT = RPC_ENDPOINT; const connection: Rpc = createRpc(RPC_ENDPOINT, COMPRESSION_ENDPOINT, PROVER_ENDPOINT) const main = async () => { /// Airdrop lamports to pay fees await confirmTx( connection, await connection.requestAirdrop(payer.publicKey, 10e9) ); await confirmTx( connection, await connection.requestAirdrop(tokenRecipient.publicKey, 1e6) ); /// Create compressed token mint const { mint, transactionSignature } = await createMint( connection, payer, payer.publicKey, 9 // Number of decimals ); console.log(`create-mint success! txId: ${transactionSignature}`); /// Mint compressed tokens to the payer's account const mintToTxId = await mintTo( connection, payer, mint, payer.publicKey, // Destination payer, 1e9 // Amount ); console.log(`Minted 1e9 tokens to ${payer.publicKey} was a success!`); console.log(`txId: ${mintToTxId}`); /// Transfer compressed tokens from payer to tokenRecipient's pubkey const transferTxId = await transfer( connection, payer, mint, 7e8, // Amount payer, // Owner tokenRecipient.publicKey // To address ); console.log(`Transfer of 7e8 ${mint} to ${tokenRecipient.publicKey} was a success!`); console.log(`txId: ${transferTxId}`); }; main(); ### [](https://www.zkcompression.com/introduction/intro-to-development#on-chain-program-development) On-chain Program Development You can write custom programs using ZK compression in Anchor or native Rust. Program Description The system program. It enforces the compressed account layout with ownership and sum checks and verifies the validity of your input state It is also invoked to create/write to compressed accounts and PDAs A compressed token implementation built on top of ZK Compression. It enforces a SPL-compatible token layout and allows for arbitrary compression/decompression between this and the SPL standard Implements state and address trees. It is used by the Light System program [](https://www.zkcompression.com/introduction/intro-to-development#build-by-example) Build by Example ---------------------------------------------------------------------------------------------------------- While you get started building with ZK Compression, use these GitHub resources available to help accelerate your journey: [](https://www.zkcompression.com/introduction/intro-to-development#developer-environments) Developer Environments ---------------------------------------------------------------------------------------------------------------------- ZK Compression is available on Localnet using `light test-validator`, Devnet, and Mainnet-Beta. [](https://www.zkcompression.com/introduction/intro-to-development#getting-support) Getting Support -------------------------------------------------------------------------------------------------------- For the best support, head to the: Remember to include as much detail as possible in your question, and please use text (not screenshots) to show error messages so other people with the same problem can find your question! [](https://www.zkcompression.com/introduction/intro-to-development#next-steps) Next Steps ---------------------------------------------------------------------------------------------- The ZK Compression primitive is the core of . To leverage ZK Compression, your custom program invokes the _Light system program_ via Cross-Program Invocation (CPI). First, ensure your development environment has installed Rust, the Solana CLI, and Anchor. If you haven't installed them, refer to this . We provide tooling for testing your on-chain program on a local Solana cluster. The `light test-validator` command, available with the , automatically initializes a local Solana cluster with the compression programs, all necessary system accounts, and syscalls activated. By default, it also starts a local Photon RPC instance and Prover node. for Solana-specific questions for program and client-related questions for RPC-related questions You're now ready to start building with ZK Compression! Head to the section, or ! [the Light protocol](https://github.com/Lightprotocol) [setup guide](https://solana.com/developers/guides/getstarted/setup-local-development) [ZK Compression CLI](https://github.com/Lightprotocol/light-protocol/blob/main/cli/README.md) [Web Example Client](https://github.com/Lightprotocol/example-web-client) [Node Example Client](https://github.com/Lightprotocol/example-nodejs-client) [Token Escrow Anchor Program](https://github.com/Lightprotocol/light-protocol/tree/light-v0.3.0/examples/token-escrow) [Solana StackExchange](https://solana.stackexchange.com/) [Light Developer Discord](https://discord.gg/CYvjBgzRFP) [Helius Developer Discord](https://discord.gg/Uzzf6a7zKr) [Client Quickstart](https://www.zkcompression.com/developers/typescript-client) [build](https://www.zkcompression.com/introduction/intro-to-development#build-by-example) [a program](https://www.zkcompression.com/introduction/intro-to-development#build-by-example) [@lightprotocol/stateless.js](https://github.com/Lightprotocol/light-protocol/tree/main/js/stateless.js) [@lightprotocol/compressed-token](https://github.com/Lightprotocol/light-protocol/tree/main/js/compressed-token) [light-sdk](https://github.com/Lightprotocol/light-protocol/tree/main/sdk) [light-system-program](https://github.com/Lightprotocol/light-protocol/tree/main/programs/system) [light-compressed-token](https://crates.io/crates/light-compressed-token) [account-compression](https://github.com/Lightprotocol/light-protocol/tree/main/programs/account-compression) [Solana documentation](https://solana.com/docs/intro/dev) [The Solana Programming Model: An Introduction to Developing on Solana](https://www.helius.dev/blog/the-solana-programming-model-an-introduction-to-developing-on-solana) [ZK Compression RPC API](https://www.zkcompression.com/developers/json-rpc-methods) [JSON RPC API](https://solana.com/docs/rpc) [here](https://www.zkcompression.com/developers/json-rpc-methods) [Helius Labs](https://github.com/helius-labs) [Photon indexer implementation](https://github.com/helius-labs/photon) [Client development](https://www.zkcompression.com/introduction/intro-to-development#client-side-development) [On-chain program development](https://www.zkcompression.com/introduction/intro-to-development#on-chain-program-development) [Run a Node](https://www.zkcompression.com/node-operators/run-a-node#photon-indexer-node) --- # Event: 1000x Hackathon | ZK Compression [PreviousIntro to Development](https://www.zkcompression.com/introduction/intro-to-development) [NextJS - v0.21.0](https://www.zkcompression.com/release-notes/js-v0.21.0) Last updated 29 days ago Was this helpful? 1000x runs in parallel to the Solana Breakout Hackathon. You can submit your project to Breakout and 1000x. Submissions for the cPOP and cSolanaPay prizes are **due Sunday, May 11 at 11:59 PM PST**. Submit here: - \- [](https://www.zkcompression.com/event/event-1000x-hackathon#submissions-are-now-open) Submissions are now open! --------------------------------------------------------------------------------------------------------------------- 1. Use ZK Compression in your hackathon project 3. You're now eligible to win prizes in 1000x [](https://www.zkcompression.com/event/event-1000x-hackathon#schedule) Schedule ------------------------------------------------------------------------------------ Start End Global Online Hackathon 14 Apr 2025 16 May 2025 Best POP interface Deadline \- **11 May 2025** Best cToken x Solana Pay Deadline . **11 May 2025** Main Track Submissions \- 16 May 2025 Judging 16 May 2025 \- [](https://www.zkcompression.com/event/event-1000x-hackathon#resources) Resources -------------------------------------------------------------------------------------- [](https://www.zkcompression.com/event/event-1000x-hackathon#judging) Judging ---------------------------------------------------------------------------------- Participants must submit their project to the hackathon before May 16, 2025, to be eligible for prizes. Once all submissions are collected, we will distribute a list to the side-track judges for evaluation. Additionally, the Breakout Hackathon's submission rules apply. Teams and individuals are evaluated on the following criteria: * Functionality * Potential impact * Novelty * Design * Extensibility The Solana Foundation cPop and cPay prizes are subject to dedicated requirements listed below\*. After the judges complete individual evaluations, they will discuss and choose the winners based on the project's weighted scores. [](https://www.zkcompression.com/event/event-1000x-hackathon#prizes) Prizes -------------------------------------------------------------------------------- Place Prize First Place $10k + Swag Second Place $5k + Swag Third Place 2 teams á $2k + Swag Best cPOP interface\* Total $15k + 2 tickets for Solana Accelerate Best cToken integration for Solana Pay\* $2k + 2 tickets for Solana Accelerate All participants who submit a project that fulfills the eligibility criteria $100 \*The Solana Foundation is sponsoring a dedicated prize pool for the best cToken Proof-of-Participation (POP) interface: The interface should: * Let creators mint experience tokens (cTokens for airdrops) * Let attendees claim them by scanning a QR code [](https://www.zkcompression.com/event/event-1000x-hackathon#faq) FAQ -------------------------------------------------------------------------- How do I submit?[](https://www.zkcompression.com/event/event-1000x-hackathon#how-do-i-submit) What are the rules?[](https://www.zkcompression.com/event/event-1000x-hackathon#what-are-the-rules) Additionally, to be eligible to score in the "1000x Hackathon", your project must: * Use compressed tokens or compressed accounts in some capacity. * Submit by May 16. * Each participant can have a maximum of 1 project submission count towards scoring in the "1000x hackathon". * The Solana Foundation cPoap and cPay prizes are subject to dedicated requirements\*. * Please note that we award the prizes and the $100 participation bounty at our sole discretion. We reserve the right not to award the participation bounty if a submission is deemed insufficient in effort or quality. Where can i access developer resources?[](https://www.zkcompression.com/event/event-1000x-hackathon#where-can-i-access-developer-resources) Where can I find ideas?[](https://www.zkcompression.com/event/event-1000x-hackathon#where-can-i-find-ideas) We encourage you to build things that you're excited about building. Where can I ask technical questions?[](https://www.zkcompression.com/event/event-1000x-hackathon#where-can-i-ask-technical-questions) Submissions are hosted on . Make sure to submit before the respective Deadlines! We have compiled a list of interesting ideas to explore during the 1000x Hackathon that can serve as inspiration: . Submit your project by May 16. The apply. Example clients (, ) Introductory posts For inspiration, we have compiled a list of interesting ideas . Check out the and Developer Discord servers! We also host for teams or individuals participating in the hackathon. 🗓️ [ST Earn](https://earn.superteam.fun/listing/1000x-hackathon/) [Project Ideas](https://github.com/Lightprotocol/1000x-hackathon/blob/main/ideas.md) [ZK Compression documentation](https://www.zkcompression.com/) [Discord chat for the hackathon](https://discord.com/invite/qCv4Y7uYmh) [here](https://docs.google.com/forms/d/e/1FAIpQLSekwFXBe009nO1fIgUHQfiAU0ILRN8y2O1XUm1qoJRZYGus-g/viewform?usp=header) [Solana Foundation Rules](https://www.colosseum.org/files/Breakout%20Hackathon%20Official%20Rules%202025.pdf) [ZK Compression documentation](https://www.zkcompression.com/event/event-1000x-hackathon) [Light Protocol Monorepo](https://github.com/lightprotocol/light-protocol) [Example programs](https://github.com/Lightprotocol/light-protocol/tree/main/examples) [web](https://github.com/Lightprotocol/example-web-client) [node](https://github.com/Lightprotocol/example-nodejs-client) [Integration guides](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens) [Blog](https://www.helius.dev/blog/solana-builders-zk-compression) [here](https://github.com/Lightprotocol/1000x-hackathon/) [Light](https://discord.gg/CYvjBgzRFP) [Helius](https://discord.gg/Uzzf6a7zKr) [office hours](https://calendly.com/swen_light/1000x-breakout-hackathon-office-hours) [cToken x SolanaPay](https://earn.superteam.fun/listing/1000x-hackathon-best-ctoken-integration-for-solana-pay/) [cPOP](https://earn.superteam.fun/listing/1000x-hackathon-best-cpop-interface/) ![](https://www.zkcompression.com/~gitbook/image?url=https%3A%2F%2F3488020389-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FDBJ4vLlhHTdkUGOiHxbB%252Fuploads%252FE5QRo8VKX9joIxMVSKSj%252F1000x_35_banner.png%3Falt%3Dmedia%26token%3D7bb64a29-7a07-468c-867f-b36c3f2dd2f5&width=768&dpr=4&quality=100&sign=83f29c83&sv=2) --- # JS - v0.21.0 | ZK Compression [PreviousEvent: 1000x Hackathon](https://www.zkcompression.com/event/event-1000x-hackathon) [NextIn a Nutshell](https://www.zkcompression.com/learn/in-a-nutshell) Last updated 1 month ago Was this helpful? This is a JS release for `@lightprotocol/stateless.js` and `@lightprotocol/compressed-token.` v0.21.0 has several important breaking changes that improve protocol scalability. If you need help migrating, we're happy to assist you. Please reach out to the team . [](https://www.zkcompression.com/release-notes/js-v0.21.0#how-to-migrate-from-v0.20.x) How to Migrate from v0.20.x ----------------------------------------------------------------------------------------------------------------------- You can find working code snippets . [](https://www.zkcompression.com/release-notes/js-v0.21.0#compress) Compress --------------------------------------------------------------------------------- Copy // old const activeStateTrees = await connection.getCachedActiveStateTreeInfo(); const { tree } = pickRandomTreeAndQueue(activeStateTrees); const compressIx = await CompressedTokenProgram.compress({ outputStateTree: tree, }); // New const treeInfos = await rpc.getStateTreeInfos(); const treeInfo = selectStateTreeInfo(treeInfos); const infos = await getTokenPoolInfos(rpc, mint); const tokenPoolInfo = selectTokenPoolInfo(infos); const compressIx = await CompressedTokenProgram.compress({ outputStateTreeInfo: treeInfo, tokenPoolInfo, }); [](https://www.zkcompression.com/release-notes/js-v0.21.0#decompress) Decompress ------------------------------------------------------------------------------------- **Old (v0.20.x)** Copy // ... const stateTreeInfos = await rpc.getCachedActiveStateTreeInfo(); const { tree } = pickRandomTreeAndQueue(stateTreeInfos) const ix = await CompressedTokenProgram.decompress({ ...rest, outputStateTree: tree, }); **New (v0.21.x)** Copy // ... const poolInfos = await getTokenPoolInfos(rpc, mint); const selectedTokenPoolInfos = selectTokenPoolInfosForDecompression( poolInfos, amount, ); const ix = await CompressedTokenProgram.decompress({ ...rest tokenPoolInfos: selectedTokenPoolInfos, }); **You can find a detailed list of all changes here:** [here](https://t.me/swen_light) [here](https://www.zkcompression.com/developers/add-compressed-token-support-to-your-wallet#decompress-spl-tokens) [light-protocol/js/compressed-token/CHANGELOG.md at b860d449b25d1943b4bc007717316913c9713be8 · Lightprotocol/light-protocolGitHub](https://github.com/Lightprotocol/light-protocol/blob/b860d449b25d1943b4bc007717316913c9713be8/js/compressed-token/CHANGELOG.md) ![Logo](https://www.zkcompression.com/~gitbook/image?url=https%3A%2F%2Fgithub.com%2Ffluidicon.png&width=20&dpr=4&quality=100&sign=77d83f0c&sv=2) --- # In a Nutshell | ZK Compression [PreviousJS - v0.21.0](https://www.zkcompression.com/release-notes/js-v0.21.0) [NextCore Concepts](https://www.zkcompression.com/learn/core-concepts) Last updated 4 months ago Was this helpful? [](https://www.zkcompression.com/learn/in-a-nutshell#high-level-system-overview) High-level System Overview ---------------------------------------------------------------------------------------------------------------- 1. **State is stored as call data in** **,** resulting in very low rent cost 2. **Transactions specify the state they access** (read/write) and include it in the transaction payload 3. **State Validation:** 1. Solana Programs the to update compressed state 1. **The protocol** **the state** (validity of existing state, sum checks, ownership checks) 2. **The protocol enforces a schema:** Classic Accounts → Compressed Accounts. have a layout similar to classic accounts 4. **State Updates:** At the end of an instruction, the new state is recorded as a log on the Solana ledger 5. **:** These nodes index the state changes, making the compressed account state available to clients via the 6. **Forester Nodes (Keeper Nodes)**: Interact with the to empty queues and rollover state trees. [**Solana's ledger**](https://www.helius.dev/blog/all-you-need-to-know-about-compression-on-solana#state-vs-ledger) [invoke](https://solana.com/docs/core/cpi) [**validates**](https://www.zkcompression.com/learn/core-concepts/validity-proofs) [Compressed accounts](https://www.zkcompression.com/learn/core-concepts/compressed-account-model) [**Photon RPC Nodes**](https://www.zkcompression.com/node-operators/run-a-node#photon-rpc-node) [ZK Compression RPC API](https://www.zkcompression.com/developers/json-rpc-methods) [Light Protocol System Program](https://www.zkcompression.com/developers/addresses-and-urls#program-ids-and-accounts-from-27th-aug-2024-onward) [Account Compression Program](https://www.zkcompression.com/developers/addresses-and-urls#program-ids-and-accounts-from-27th-aug-2024-onward) --- # Lifecycle of a Transaction | ZK Compression [PreviousValidity Proofs](https://www.zkcompression.com/learn/core-concepts/validity-proofs) [NextLimitations](https://www.zkcompression.com/learn/core-concepts/limitations) Last updated 2 months ago Was this helpful? ZK Compression transactions are fully compatible with Solana's Transaction and Versioned Transaction formats. There are three key nuances in building transactions with compressed accounts as compared to regular accounts: * Instructions must specify the list of all compressed accounts being read or written to. To read or write to a compressed account, the instruction must send the current account state on-chain and prove its validity * Each unique state tree that gets read or written to (via any compressed account) needs to be specified as per Solana's regular on-chain * To read any compressed account state on-chain, the client must send a validity proof alongside the instruction data to the chain. Depending on your program logic, the validity proof can prove A) the validity of all specified read accounts and B) the non-existence of a specified PDA within the compressed address space, e.g., for creating a new compressed PDA account We can express a transaction more generally as: `(state, validityProof) -> state transition -> state'` Here's what this looks like when updating a single compressed PDA account: The custom Solana program executing the state transition _Data_ -> _Data'_ should require its client to pack the instructions efficiently. In the above scenario, the total data that's sent to the chain is: `address (same)`, `owner program (same)`, `data`, `data'-data`, `validity proof` The compressed account after its update looks like this: [](https://www.zkcompression.com/learn/core-concepts/lifecycle-of-a-transaction#on-chain-protocol-execution) On-chain Protocol Execution --------------------------------------------------------------------------------------------------------------------------------------------- To write compressed state, a custom caller program must invoke the Light System Program via CPI. The system program then does the following: In this example, we assume that the client previously created said compressed account and thereafter fetched its compressed account info from an Runs relevant checks (, etc.) the "old" leaf of the compressed account that is being written to the new compressed account hash to the state tree and advances the tree's state root the new compressed account state onto the Solana ledger An then parses the transaction and compressed state and provides the read state to clients via the [sum check](https://github.com/Lightprotocol/light-protocol/blob/v.1.0.0/programs/system/src/invoke/verify_state_proof.rs#L204-L210) [Verifies the validity proof](https://github.com/Lightprotocol/light-protocol/blob/v.1.0.0/programs/system/src/invoke/processor.rs#L209-L214) [Nullifies](https://github.com/Lightprotocol/light-protocol/blob/v.1.0.0/programs/system/src/invoke/processor.rs#L209-L214) [Appends](https://github.com/Lightprotocol/light-protocol/blob/v.1.0.0/programs/system/src/invoke/processor.rs#L245-L254) [Emits](https://github.com/Lightprotocol/light-protocol/blob/v.1.0.0/programs/system/src/invoke/processor.rs#L272-L279) [account access lists](https://solana.com/docs/core/transactions#array-of-account-addresses) [ZK Compression RPC API](https://www.zkcompression.com/developers/json-rpc-methods) [RPC node](https://www.zkcompression.com/node-operators/run-a-node#photon-indexer-node) [RPC node](https://www.zkcompression.com/node-operators/run-a-node#photon-indexer-node) Simplified: Read and Write compressed accounts Full representation of a compressed account with PDA ![](https://www.zkcompression.com/~gitbook/image?url=https%3A%2F%2F3488020389-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FDBJ4vLlhHTdkUGOiHxbB%252Fuploads%252FYlt1ftz6KJz3Zc0VLOIB%252Fimage.png%3Falt%3Dmedia%26token%3Df225cb5d-a1e9-40f0-b91c-289b5dbcf741&width=768&dpr=4&quality=100&sign=b45ef73f&sv=2) ![](https://www.zkcompression.com/~gitbook/image?url=https%3A%2F%2F3488020389-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FDBJ4vLlhHTdkUGOiHxbB%252Fuploads%252FBpJx0y1hjF3bTXmb3QhL%252Fimage.png%3Falt%3Dmedia%26token%3D272a064a-0b01-4508-9940-dfbe2134ca69&width=768&dpr=4&quality=100&sign=fc364180&sv=2) --- # State Trees | ZK Compression [PreviousCompressed Account Model](https://www.zkcompression.com/learn/core-concepts/compressed-account-model) [NextValidity Proofs](https://www.zkcompression.com/learn/core-concepts/validity-proofs) Last updated 5 months ago Was this helpful? The protocol stores compressed state in multiple state trees A state tree is a binary that organizes data into a tree structure where each parent node is the hash of its two children nodes. This leads to a single unique root hash that allows for efficient cryptographic verification of the integrity of all the leaves in the tree. The hash of each is stored as a leaf in a state tree: Note that each compressed account hash includes the public key of the state tree's respective on-chain account (i.e., `state tree hash`) and the compressed account's position in the tree (i.e., `leafIndex`). This ensures that each account hash is globally unique. Each state tree has a single on-chain state tree account that stores only the tree's final root hash and other metadata. Storing the final tree root hash on-chain allows the protocol to efficiently verify the validity of any leaf (compressed account) in the tree. The raw state can thus be stored as calldata in the much cheaper Solana ledger space while preserving Solana's security guarantees. [Merkle tree](https://brilliant.org/wiki/merkle-tree/) [compressed account](https://www.zkcompression.com/learn/core-concepts/compressed-account-model) A small binary Merkle tree (depth 2) Each compressed account hash is a leaf in the state tree ![](https://www.zkcompression.com/~gitbook/image?url=https%3A%2F%2F3488020389-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FDBJ4vLlhHTdkUGOiHxbB%252Fuploads%252F6scYgSo19Xf3cgtlUKPC%252Fimage.png%3Falt%3Dmedia%26token%3Dde11ff14-2f7c-4844-91d2-7e29275db4e3&width=768&dpr=4&quality=100&sign=b8fc9f1e&sv=2) ![](https://www.zkcompression.com/~gitbook/image?url=https%3A%2F%2F3488020389-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FDBJ4vLlhHTdkUGOiHxbB%252Fuploads%252FWDP8Fagc0iHHkXh7e0EP%252FScreenshot%25202024-05-10%2520at%252006.37.41.png%3Falt%3Dmedia%26token%3D1309700a-334d-4634-9e6f-50a2e5281083&width=768&dpr=4&quality=100&sign=a4b98816&sv=2) --- # Validity Proofs | ZK Compression [PreviousState Trees](https://www.zkcompression.com/learn/core-concepts/state-trees) [NextLifecycle of a Transaction](https://www.zkcompression.com/learn/core-concepts/lifecycle-of-a-transaction) Last updated 5 months ago Was this helpful? Validity proofs are succinct zero-knowledge proofs (ZKPs) that can prove the existence of compressed accounts as leaves within state trees while maintaining a constant 128-byte size. These proofs are generated off-chain and verified on-chain. ZK Compression uses , a well-known , for its proof system. The protocol leverages ZKP generation and verification under the hood, so you don't have to learn about ZK directly to use ZK Compression. [Groth16](https://docs.rs/groth16-solana/latest/groth16_solana/) [pairing-based](https://en.wikipedia.org/wiki/Pairing-based_cryptography) [zk-SNARK](https://www.helius.dev/blog/zero-knowledge-proofs-its-applications-on-solana#-zk-snarks-and-circuits) A Merkle proof path (purple nodes) consists of all sibling node hashes required to calculate the final root node. ![](https://www.zkcompression.com/~gitbook/image?url=https%3A%2F%2F3488020389-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FDBJ4vLlhHTdkUGOiHxbB%252Fuploads%252FGvZDdtCn4P9S6BU2liD3%252FScreenshot%25202024-05-13%2520at%252014.40.53.png%3Falt%3Dmedia%26token%3D722f21e0-bdd8-4d45-96e2-133522f11d0c&width=768&dpr=4&quality=100&sign=7127ccb8&sv=2) --- # Compressed Account Model | ZK Compression [PreviousCore Concepts](https://www.zkcompression.com/learn/core-concepts) [NextState Trees](https://www.zkcompression.com/learn/core-concepts/state-trees) Last updated 9 months ago Was this helpful? This guide assumes that you're familiar with . [](https://www.zkcompression.com/learn/core-concepts/compressed-account-model#regular-versus-compressed-accounts) Regular versus Compressed Accounts --------------------------------------------------------------------------------------------------------------------------------------------------------- ZK compressed state is stored in compressed accounts. Compressed accounts are similar to regular Solana accounts but with four main differences: * Each compressed account can be identified by its hash * Each write to a compressed account changes its hash * An `address` can optionally be set as a permanent unique ID of the compressed account * All compressed accounts are stored in . Only the tree's state root (i.e., a small fingerprint of all compressed accounts) is stored in the on-chain account space These differences allow the protocol to store states as calldata in the less expensive Solana ledger space instead of costly on-chain account space To understand the similarities and differences between Solana's regular account model and compressed accounts, let's first look at compressed accounts with Program-Derived Addresses (PDAs) > If you don't know what PDAs are, read first [](https://www.zkcompression.com/learn/core-concepts/compressed-account-model#compressed-pda-accounts) Compressed PDA Accounts ----------------------------------------------------------------------------------------------------------------------------------- Like regular accounts, each compressed PDA account can be identified by its unique persistent address, represented as 32 bytes in the format of a `PublicKey`. Like PDAs, compressed account addresses don't belong to a private key; rather, they're derived from the program that owns them The compressed PDA account layout is similar to Solana's regular PDA account layout — it has the **Data**, **Lamports**, **Owner**, and **Address** fields. The **Data** field stores the program state. Notice the enshrined **AccountData** structure: **Discriminator**, **Data**, **DataHash**: ### [](https://www.zkcompression.com/learn/core-concepts/compressed-account-model#address-and-hash) Address & Hash The `address` field is optional for compressed accounts because ensuring that the address of a new account is unique incurs additional computational overhead, and not all use cases need the uniqueness property of addresses Instead, each compressed account can be identified by its hash, regardless of whether it has an address * Use the address field wherever the state must be unique (such as for NFTs or certain PDAs) * You don't need the address for any fungible state (e.g., fungible tokens) By definition, whenever the data of a compressed account changes, its hash changes. This impacts how developers interact with fungible state: The framework reserves the first 8 bytes of a regular account's data field for the discriminator. This helps programs distinguish between different program-owned accounts. The default compressed account layout is opinionated in this regard and enforces a discriminator in the Data field. You can ignore the **DataHash** field for now; we cover its importance for ZK Compression later. Check out the section to see what using hashes instead of addresses looks like in practice Visit the section to understand why using the account's hash as its ID makes sense for the compression protocol [Anchor](https://www.anchor-lang.com/) [State Trees](https://www.zkcompression.com/learn/core-concepts/state-trees) [Solana's account model](https://solana.com/docs/core/accounts) [sparse state trees](https://www.zkcompression.com/learn/core-concepts/state-trees) [this explainer](https://solana.com/docs/core/pda) Compressed PDA Accounts Compressed PDA Account with AccountData ![](https://www.zkcompression.com/~gitbook/image?url=https%3A%2F%2F3488020389-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FDBJ4vLlhHTdkUGOiHxbB%252Fuploads%252FikMGOt2gYlH0YAyIDMGR%252Fimage.png%3Falt%3Dmedia%26token%3D61e5f88c-7fba-4506-9be5-a6b673831878&width=768&dpr=4&quality=100&sign=548492e0&sv=2) ![](https://www.zkcompression.com/~gitbook/image?url=https%3A%2F%2F3488020389-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FDBJ4vLlhHTdkUGOiHxbB%252Fuploads%252FgOUc2sZELSEWVeT5h2cI%252Fimage.png%3Falt%3Dmedia%26token%3D40d84b6a-d4b6-4224-8d20-a92c8a4355f4&width=768&dpr=4&quality=100&sign=33ca4324&sv=2) [examples](https://www.zkcompression.com/introduction/intro-to-development#build-by-example) --- # Core Concepts | ZK Compression ZK Compression is a new primitive on Solana that drastically reduces on-chain state costs while maintaining security, composability, and performance. ZK Compression allows developers to efficiently scale their applications to millions of users with the help of zero-knowledge proofs. In the following sections, we'll dive into the core concepts that make ZK Compression possible: * **Compressed Account Model**: Understand how compressed accounts differ from regular Solana accounts (not much!) and how they enhance efficiency. * **State Trees**: Learn about the Merkle tree structure used to store compressed accounts and how it minimizes on-chain storage. * **Validity Proofs**: Explore how the protocol uses zero-knowledge proofs to verify data validity while keeping proof sizes small. * **Lifecycle of a Transaction**: Follow the journey of a ZK-compressed transaction from creation to execution. * **Limitations and Considerations**: Discover the trade-offs and scenarios where ZK Compression may or may not be the best solution. [PreviousIn a Nutshell](https://www.zkcompression.com/learn/in-a-nutshell) [NextCompressed Account Model](https://www.zkcompression.com/learn/core-concepts/compressed-account-model) Last updated 9 months ago Was this helpful? --- # TypeScript Client | ZK Compression [PreviousLimitations](https://www.zkcompression.com/learn/core-concepts/limitations) [NextJSON RPC Methods](https://www.zkcompression.com/developers/json-rpc-methods) Last updated 4 months ago Was this helpful? [](https://www.zkcompression.com/developers/typescript-client#what-is-solana-web3-js) Stateless.js API Reference Guide --------------------------------------------------------------------------------------------------------------------------- The lets you build Javascript clients that interact with the ZK Compression primitive via the . [](https://www.zkcompression.com/developers/typescript-client#installation) Installation --------------------------------------------------------------------------------------------- Package Manager Command NPM Yarn [](https://www.zkcompression.com/developers/typescript-client#basics) Basics --------------------------------------------------------------------------------- ### [](https://www.zkcompression.com/developers/typescript-client#connection) Rpc The `Rpc` connection is used to interact with the . It's a thin wrapper extending with compression-related endpoints, such as `getCompressedAccount`, `getCompressedTokenBalancesByOwner`, and more. **Example Usage with Devnet** Copy const stateless = require("@lightprotocol/stateless.js"); /// Helius exposes Solana and compression RPC endpoints through a single URL const RPC_ENDPOINT = "https://devnet.helius-rpc.com?api-key="; const COMPRESSION_RPC_ENDPOINT = RPC_ENDPOINT; const PROVER_ENDPOINT = RPC_ENDPOINT const connection: Rpc = createRpc(RPC_ENDPOINT, COMPRESSION_RPC_ENDPOINT, PROVER_ENDPOINT) async function main() { let slot = await connection.getSlot(); console.log(slot); let health = await connection.getIndexerHealth(slot); console.log(health); // "Ok" } main(); [](https://www.zkcompression.com/developers/typescript-client#quickstart) Quickstart ----------------------------------------------------------------------------------------- ### [](https://www.zkcompression.com/developers/typescript-client#starting-the-test-validator-for-local-development) Starting the `test-validator` for Local Development Copy light test-validator The command above will start a single-node Solana cluster, an RPC node, and a prover node at ports 8899, 8784, and 3001. ### [](https://www.zkcompression.com/developers/typescript-client#creating-and-sending-transactions) Creating and Sending Transactions #### [](https://www.zkcompression.com/developers/typescript-client#creating-minting-and-transferring-a-compressed-token) Creating, Minting, and Transferring a Compressed Token This example uses the **compressed token program**, which is built using ZK Compression and offers an SPL-compatible token layout. Copy import { LightSystemProgram, Rpc, confirmTx, createRpc, } from "@lightprotocol/stateless.js"; import { createMint, mintTo, transfer } from "@lightprotocol/compressed-token"; import { Keypair } from "@solana/web3.js"; const payer = Keypair.generate(); const tokenRecipient = Keypair.generate(); /// Localnet const connection: Rpc = createRpc(); const main = async () => { /// Airdrop lamports to pay fees await confirmTx( connection, await connection.requestAirdrop(payer.publicKey, 10e9) ); await confirmTx( connection, await connection.requestAirdrop(tokenRecipient.publicKey, 1e6) ); /// Create a compressed token mint const { mint, transactionSignature } = await createMint( connection, payer, payer.publicKey, 9 // Number of decimals ); console.log(`create-mint success! txId: ${transactionSignature}`); /// Mint compressed tokens to the payer's account const mintToTxId = await mintTo( connection, payer, mint, payer.publicKey, // Destination payer, 1e9 // Amount ); console.log(`Minted 1e9 tokens to ${payer.publicKey} was a success!`); console.log(`txId: ${mintToTxId}`); /// Transfer compressed tokens const transferTxId = await transfer( connection, payer, mint, 7e8, // Amount payer, // Owner tokenRecipient.publicKey // To address ); console.log(`Transfer of 7e8 ${mint} to ${tokenRecipient.publicKey} was a success!`); console.log(`txId: ${transferTxId}`); }; main(); ### [](https://www.zkcompression.com/developers/typescript-client#creating-lookup-tables) Creating Lookup Tables Copy import { Rpc, confirmTx, createRpc } from "@lightprotocol/stateless.js"; import { createTokenProgramLookupTable } from "@lightprotocol/compressed-token"; import { Keypair, PublicKey} from "@solana/web3.js"; import { RPC_ENDPOINT } from "./constants"; const payer = Keypair.generate(); const authority = payer; const additionalTokenMints : PublicKey[] = []; const additionalAccounts : PublicKey[] = []; // Localnet const connection: Rpc = createRpc(); const main = async () => { /// airdrop lamports to pay gas and rent await confirmTx( connection, await connection.requestAirdrop(payer.publicKey, 1e7) ); /// Create LUT const { address } = await createTokenProgramLookupTable( connection, payer, authority, additionalTokenMints, additionalAccounts ); console.log("Created lookup table:", address.toBase58()); }; main(); ### [](https://www.zkcompression.com/developers/typescript-client#examples) Examples To get started building with examples, check out these GitHub repositories: Visit the section for the full list of compression endpoints supported in `Rpc` . For public networks, we provide for Light's common program IDs and accounts Copy npm install --save \ @lightprotocol/stateless.js \ @lightprotocol/compressed-token \ @solana/web3.js \ @lightprotocol/zk-compression-cli Copy yarn add \ @lightprotocol/stateless.js \ @solana/web3.js \ @lightprotocol/zk-compression-cli [@lightprotocol/stateless.js library](https://www.npmjs.com/package/@lightprotocol/stateless.js) [ZK Compression JSON RPC API](https://www.zkcompression.com/developers/json-rpc-methods) [Source Documentation](https://github.com/Lightprotocol/light-protocol/blob/main/js/stateless.js/src/rpc.ts) [ZK Compression JSON RPC](https://www.zkcompression.com/developers/json-rpc-methods) [Solana's web3.js `Connection` class](https://solana-labs.github.io/solana-web3.js/classes/Connection.html) [JSON RPC Methods](https://www.zkcompression.com/developers/json-rpc-methods) [Web Example Client](https://github.com/Lightprotocol/example-web-client) [Node Example Client](https://github.com/Lightprotocol/example-nodejs-client) [Token Escrow Program Example](https://github.com/Lightprotocol/light-protocol/tree/light-v0.3.0/examples/token-escrow) [shared lookup tables](https://www.zkcompression.com/developers/addresses-and-urls#lookup-tables) --- # Limitations | ZK Compression [PreviousLifecycle of a Transaction](https://www.zkcompression.com/learn/core-concepts/lifecycle-of-a-transaction) [NextTypeScript Client](https://www.zkcompression.com/developers/typescript-client) Last updated 9 months ago Was this helpful? Before using ZK Compression to scale your application state, consider the following limitations of compressed accounts: [](https://www.zkcompression.com/learn/core-concepts/limitations#general-recommendation) General Recommendation -------------------------------------------------------------------------------------------------------------------- Consider which accounts in your application benefit from ZK Compression and which don't. You can use both types for different parts of your application! It may be preferred for an account _not_ to be permanently compressed if: * The account gets updated very frequently within a single block (e.g., shared liquidity pools in a DeFi protocol). * You expect the lifetime number of writes to the same account to be very large (>>1000x). * The account stores large amounts of data, and you need to access a large part of it (>1kb) inside one on-chain transaction. [](https://www.zkcompression.com/learn/core-concepts/limitations#larger-transaction-size) **Larger Transaction Size** -------------------------------------------------------------------------------------------------------------------------- Solana's transaction size limit is 1232 Bytes. Transactions exceeding this limit will fail. ZK Compression increases your transaction size in two ways: * 128 bytes must be reserved for the validity proof, which is a constant size per transaction, assuming the transaction reads from at least one compressed account. * You must send the account data you want to read/write on-chain. [](https://www.zkcompression.com/learn/core-concepts/limitations#high-compute-unit-usage) **High Compute Unit Usage** -------------------------------------------------------------------------------------------------------------------------- System CU usage: * ~100,000 CU for validity proof verification, which is a constant size per transaction, assuming the transaction reads from at least one compressed account * ~6,000 CU per compressed account read/write **Example**: a typical compressed token transfer uses around 292,000 CU. Higher CU usage can: * **Lead to usage limits:** The total CU limit per transaction is 1,400,000 CU, and the per-block write lock limit per State tree is 12,000,000 CU. [](https://www.zkcompression.com/learn/core-concepts/limitations#state-cost-per-transaction) State Cost Per Transaction ---------------------------------------------------------------------------------------------------------------------------- Each write operation incurs a small additional network cost. If you expect a single compressed account to amass a large amount of state updates, the lifetime cost of the compressed account may be higher than its uncompressed equivalent, which currently has a fixed per-byte rent cost at creation. Type Lamports Notes Solana base fee 5000 per signature Compensates validators for processing transactions Write new compressed account state ~300 per leaf (default) Nullify old compressed account state 5000 per transaction Create addresses 5000 per transaction Same as nullify [](https://www.zkcompression.com/learn/core-concepts/limitations#next-steps) Next Steps -------------------------------------------------------------------------------------------- ~100,000 CU system use (state tree hashing et al.) **Require your users to increase their** **during congestion:** Whenever Solana's global per-block CU limit (48,000,000 CU) is reached, validator clients may prioritize transactions with higher per-CU priority fees. Whenever a writes to a compressed account, it nullifies the previous compressed account state and appends the new compressed account as a leaf to the state tree. Both of these actions incur costs that add to Solana's base fee. Depends on tree depth: ~300 for the default depth of `26` Reimburses the cost of running a Forester transaction. The current default Forester node implementation can be found Now you're familiar with the core concepts of ZK Compression, you're ready to take the next step! Dive into or with ZK Compression, or learn how to . For those interested in learning more about the fundamentals of ZK and its applications on Solana, we recommend reading the following: (2tree\_depth×tree\_account\_rent\_cost×rollover\_threshold)\\left( 2^{\\text{tree\\\_depth}} \\times \\text{tree\\\_account\\\_rent\\\_cost} \\times \\text{rollover\\\_threshold} \\right) (2tree\_depth×tree\_account\_rent\_cost×rollover\_threshold) [Poseidon](https://eprint.iacr.org/2019/458.pdf) [**priority fee**](https://solana.com/developers/guides/advanced/how-to-use-priority-fees) [transaction](https://www.zkcompression.com/learn/core-concepts/lifecycle-of-a-transaction) [building a program](https://www.zkcompression.com/introduction/intro-to-development#on-chain-program-development) [application](https://www.zkcompression.com/introduction/intro-to-development#client-side-development) [set up and run your own node](https://www.zkcompression.com/node-operators/run-a-node) [Zero-Knowledge Proofs: An Introduction to the Fundamentals](https://www.helius.dev/blog/zero-knowledge-proofs-an-introduction-to-the-fundamentals) [Zero-Knowledge Proofs: Its Applications on Solana](https://www.helius.dev/blog/zero-knowledge-proofs-its-applications-on-solana) [Larger Transaction Size](https://www.zkcompression.com/learn/core-concepts/limitations#larger-transaction-size) [High Compute Unit Usage](https://www.zkcompression.com/learn/core-concepts/limitations#high-compute-unit-usage) [Per-Transaction State Cost](https://www.zkcompression.com/learn/core-concepts/limitations#per-transaction-state-cost) [here](https://www.zkcompression.com/node-operators/run-a-node#light-forester-node) --- # JSON RPC Methods | ZK Compression [PreviousTypeScript Client](https://www.zkcompression.com/developers/typescript-client) [NextgetCompressedAccount](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedaccount) Last updated 8 months ago Was this helpful? [getCompressedAccount](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedaccount) [getCompressedBalance](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedbalance) [getCompressedTokenAccountBalance](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedtokenaccountbalance) [getCompressedBalanceByOwner](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedbalancebyowner) [getCompressedMintTokenHolders](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedminttokenholders) [getCompressedTokenBalancesByOwnerV2](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedtokenbalancesbyownerv2) [getCompressedAccountsByOwner](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedaccountsbyowner) [getMultipleCompressedAccounts](https://www.zkcompression.com/developers/json-rpc-methods/getmultiplecompressedaccounts) [getCompressedTokenAccountsByOwner](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedtokenaccountsbyowner) [getCompressedTokenAccountsByDelegate](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedtokenaccountsbydelegate) [getTransactionWithCompressionInfo](https://www.zkcompression.com/developers/json-rpc-methods/gettransactionwithcompressioninfo) [getCompressedAccountProof](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedaccountproof) [getMultipleCompressedAccountProofs](https://www.zkcompression.com/developers/json-rpc-methods/getmultiplecompressedaccountproofs) [getMultipleNewAddressProofs](https://www.zkcompression.com/developers/json-rpc-methods/getmultiplenewaddressproofs) [getValidityProof](https://www.zkcompression.com/developers/json-rpc-methods/getvalidityproof) [getCompressionSignaturesForAccount](https://www.zkcompression.com/developers/json-rpc-methods/getcompressionsignaturesforaccount) [getCompressionSignaturesForAddress](https://www.zkcompression.com/developers/json-rpc-methods/getcompressionsignaturesforaddress) [getCompressionSignaturesForOwner](https://www.zkcompression.com/developers/json-rpc-methods/getcompressionsignaturesforowner) [getCompressionSignaturesForTokenOwner](https://www.zkcompression.com/developers/json-rpc-methods/getcompressionsignaturesfortokenowner) [getLatestCompressionSignatures](https://www.zkcompression.com/developers/json-rpc-methods/getlatestcompressionsignatures) [getLatestNonVotingSignatures](https://www.zkcompression.com/developers/json-rpc-methods/getlatestnonvotingsignatures) [getIndexerSlot](https://www.zkcompression.com/developers/json-rpc-methods/getindexerslot) [getIndexerHealth](https://www.zkcompression.com/developers/json-rpc-methods/getindexerhealth) --- # getCompressedAccount | ZK Compression [PreviousJSON RPC Methods](https://www.zkcompression.com/developers/json-rpc-methods) [NextgetCompressedBalance](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedbalance) Last updated 9 months ago Was this helpful? Returns the compressed account with the given address or hash --- # getCompressedTokenAccountBalance | ZK Compression [PreviousgetCompressedBalance](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedbalance) [NextgetCompressedBalanceByOwner](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedbalancebyowner) Last updated 9 months ago Was this helpful? Returns the balance for a given token account --- # getCompressedBalance | ZK Compression [PreviousgetCompressedAccount](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedaccount) [NextgetCompressedTokenAccountBalance](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedtokenaccountbalance) Last updated 9 months ago Was this helpful? Returns the balance for the compressed account with the given address or hash post https://mainnet.helius-rpc.com?api-key=/ Body idstring · enumRequired An ID to identify the request. Possible values: `test-account` jsonrpcstring · enumRequired The version of the JSON-RPC protocol. Possible values: `2.0` methodstring · enumRequired The name of the method to invoke. Possible values: `getCompressedAccountBalance` paramsobjectRequired Request for compressed account data Default: `{"address":null,"hash":"11111111111111111111111111111111"}`Example: `{"address":null,"hash":"11111111111111111111111111111111"}` Show properties Responses 200Success application/json Responseobject Show properties 429 Exceeded rate limit. application/json 500 The server encountered an unexpected condition that prevented it from fulfilling the request. application/json post / HTTP HTTPcURLJavaScriptPython Copy POST / HTTP/1.1 Host: mainnet.helius-rpc.com Content-Type: application/json Accept: */* Content-Length: 144 { "id": "test-account", "jsonrpc": "2.0", "method": "getCompressedAccountBalance", "params": { "address": null, "hash": "11111111111111111111111111111111" } } Test it 200Success Copy { "context": { "slot": 100 }, "value": 100 } --- # getCompressedMintTokenHolders | ZK Compression [PreviousgetCompressedBalanceByOwner](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedbalancebyowner) [NextgetCompressedTokenBalancesByOwnerV2](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedtokenbalancesbyownerv2) Last updated 7 months ago Was this helpful? post https://mainnet.helius-rpc.com?api-key=/ Body idstring · enumRequired An ID to identify the request. Possible values: `test-account` jsonrpcstring · enumRequired The version of the JSON-RPC protocol. Possible values: `2.0` methodstring · enumRequired The name of the method to invoke. Possible values: `getCompressedMintTokenHolders` paramsobjectRequired Show properties Responses 200Success application/json Responseobject Show properties 429 Exceeded rate limit. application/json 500 The server encountered an unexpected condition that prevented it from fulfilling the request. application/json post / HTTP HTTPcURLJavaScriptPython Copy POST / HTTP/1.1 Host: mainnet.helius-rpc.com Content-Type: application/json Accept: */* Content-Length: 177 { "id": "test-account", "jsonrpc": "2.0", "method": "getCompressedMintTokenHolders", "params": { "cursor": "3J98t1WpEZ73CNm", "limit": 1, "mint": "111111152P2r5yt6odmBLPsFCLBrFisJ3aS7LqLAT" } } Test it 200Success Copy { "context": { "slot": 100 }, "value": { "cursor": "3J98t1WpEZ73CNm", "items": [\ {\ "balance": 100,\ "owner": "111111152P2r5yt6odmBLPsFCLBrFisJ3aS7LqLAT"\ }\ ] } } --- # getCompressedAccountsByOwner | ZK Compression [PreviousgetCompressedTokenBalancesByOwnerV2](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedtokenbalancesbyownerv2) [NextgetMultipleCompressedAccounts](https://www.zkcompression.com/developers/json-rpc-methods/getmultiplecompressedaccounts) Last updated 9 months ago Was this helpful? Returns the owner's compressed accounts. This is a paginated endpoint --- # getCompressedBalanceByOwner | ZK Compression [PreviousgetCompressedTokenAccountBalance](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedtokenaccountbalance) [NextgetCompressedMintTokenHolders](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedminttokenholders) Last updated 9 months ago Was this helpful? Returns the total balance of the owner's compressed accounts --- # getMultipleCompressedAccountProofs | ZK Compression [PreviousgetCompressedAccountProof](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedaccountproof) [NextgetMultipleNewAddressProofs](https://www.zkcompression.com/developers/json-rpc-methods/getmultiplenewaddressproofs) Last updated 9 months ago Was this helpful? Returns multiple proofs used by the compression program to verify the accounts' validity post https://mainnet.helius-rpc.com?api-key=/ Body idstring · enumRequired An ID to identify the request. Possible values: `test-account` jsonrpcstring · enumRequired The version of the JSON-RPC protocol. Possible values: `2.0` methodstring · enumRequired The name of the method to invoke. Possible values: `getMultipleCompressedAccountProofs` paramsstring\[\]Required A 32-byte hash represented as a base58 string. Example: `11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP` Responses 200Success application/json Responseobject Show properties 429 Exceeded rate limit. application/json 500 The server encountered an unexpected condition that prevented it from fulfilling the request. application/json post / HTTP HTTPcURLJavaScriptPython Copy POST / HTTP/1.1 Host: mainnet.helius-rpc.com Content-Type: application/json Accept: */* Content-Length: 138 { "id": "test-account", "jsonrpc": "2.0", "method": "getMultipleCompressedAccountProofs", "params": [\ "11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP"\ ] } Test it 200Success Copy { "context": { "slot": 100 }, "value": [\ {\ "hash": "11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP",\ "leafIndex": 1,\ "merkleTree": "11111117SQekjmcMtR25wEPPiL6m1Mb5586NkLL4X",\ "proof": [\ "11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP"\ ],\ "root": "11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP",\ "rootSeq": 1\ }\ ] } --- # getCompressedTokenAccountsByOwner | ZK Compression [PreviousgetMultipleCompressedAccounts](https://www.zkcompression.com/developers/json-rpc-methods/getmultiplecompressedaccounts) [NextgetCompressedTokenAccountsByDelegate](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedtokenaccountsbydelegate) Last updated 9 months ago Was this helpful? Returns the compressed token accounts owned by a certain account --- # getCompressedTokenAccountsByDelegate | ZK Compression [PreviousgetCompressedTokenAccountsByOwner](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedtokenaccountsbyowner) [NextgetTransactionWithCompressionInfo](https://www.zkcompression.com/developers/json-rpc-methods/gettransactionwithcompressioninfo) Last updated 9 months ago Was this helpful? Returns the compressed token accounts that are partially or fully delegated to the given delegate. This is a paginated endpoint --- # getCompressedAccountProof | ZK Compression [PreviousgetTransactionWithCompressionInfo](https://www.zkcompression.com/developers/json-rpc-methods/gettransactionwithcompressioninfo) [NextgetMultipleCompressedAccountProofs](https://www.zkcompression.com/developers/json-rpc-methods/getmultiplecompressedaccountproofs) Last updated 9 months ago Was this helpful? Returns a proof the compression program uses to verify that the account is valid post https://mainnet.helius-rpc.com?api-key=/ Body idstring · enumRequired An ID to identify the request. Possible values: `test-account` jsonrpcstring · enumRequired The version of the JSON-RPC protocol. Possible values: `2.0` methodstring · enumRequired The name of the method to invoke. Possible values: `getCompressedAccountProof` paramsobjectRequired Show properties Responses 200Success application/json Responseobject Show properties 429 Exceeded rate limit. application/json 500 The server encountered an unexpected condition that prevented it from fulfilling the request. application/json post / HTTP HTTPcURLJavaScriptPython Copy POST / HTTP/1.1 Host: mainnet.helius-rpc.com Content-Type: application/json Accept: */* Content-Length: 136 { "id": "test-account", "jsonrpc": "2.0", "method": "getCompressedAccountProof", "params": { "hash": "11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP" } } Test it 200Success Copy { "context": { "slot": 100 }, "value": { "hash": "11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP", "leafIndex": 1, "merkleTree": "11111117353mdUKehx9GW6JNHznGt5oSZs9fWkVkB", "proof": [\ "11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP"\ ], "root": "11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP", "rootSeq": 1 } } --- # getCompressedTokenBalancesByOwnerV2 | ZK Compression [PreviousgetCompressedMintTokenHolders](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedminttokenholders) [NextgetCompressedAccountsByOwner](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedaccountsbyowner) Last updated 6 months ago Was this helpful? Returns the token balances for a given owner. This is a paginated endpoint. The V2 version solves a minor naming issue. post https://mainnet.helius-rpc.com?api-key=/ Body idstring · enumRequired An ID to identify the request. Possible values: `test-account` jsonrpcstring · enumRequired The version of the JSON-RPC protocol. Possible values: `2.0` methodstring · enumRequired The name of the method to invoke. Possible values: `getCompressedTokenBalancesByOwnerV2` paramsobjectRequired Show properties Responses 200Success application/json Responseobject Show properties 429 Exceeded rate limit. application/json 500 The server encountered an unexpected condition that prevented it from fulfilling the request. application/json post / HTTP HTTPcURLJavaScriptPython Copy POST / HTTP/1.1 Host: mainnet.helius-rpc.com Content-Type: application/json Accept: */* Content-Length: 235 { "id": "test-account", "jsonrpc": "2.0", "method": "getCompressedTokenBalancesByOwnerV2", "params": { "cursor": "3J98t1WpEZ73CNm", "limit": 1, "mint": "11111114DhpssPJgSi1YU7hCMfYt1BJ334YgsffXm", "owner": "11111114DhpssPJgSi1YU7hCMfYt1BJ334YgsffXm" } } Test it 200Success Copy { "context": { "slot": 100 }, "value": { "cursor": "3J98t1WpEZ73CNm", "items": [\ {\ "balance": 100,\ "mint": "11111114DhpssPJgSi1YU7hCMfYt1BJ334YgsffXm"\ }\ ] } } --- # getCompressionSignaturesForTokenOwner | ZK Compression [PreviousgetCompressionSignaturesForOwner](https://www.zkcompression.com/developers/json-rpc-methods/getcompressionsignaturesforowner) [NextgetLatestCompressionSignatures](https://www.zkcompression.com/developers/json-rpc-methods/getlatestcompressionsignatures) Last updated 10 months ago Was this helpful? ![Page cover image](https://static.gitbook.com/_next/static/media/default-page-cover.a2ccd7e9.svg) --- # getCompressionSignaturesForAccount | ZK Compression [PreviousgetValidityProof](https://www.zkcompression.com/developers/json-rpc-methods/getvalidityproof) [NextgetCompressionSignaturesForAddress](https://www.zkcompression.com/developers/json-rpc-methods/getcompressionsignaturesforaddress) Last updated 9 months ago Was this helpful? Return the signatures of the transactions that closed or opened a compressed account with the given hash. This is a paginated endpoint --- # Addresses and URLs | ZK Compression ### [](https://www.zkcompression.com/developers/addresses-and-urls#mainnet-urls) Mainnet URLs Network Address (RPC) https://mainnet.helius-rpc.com?api-key= Photon RPC API https://mainnet.helius-rpc.com?api-key= ### [](https://www.zkcompression.com/developers/addresses-and-urls#devnet-urls) Devnet URLs Network Address (RPC) https://devnet.helius-rpc.com?api-key= Photon RPC API https://devnet.helius-rpc.com?api-key= ### [](https://www.zkcompression.com/developers/addresses-and-urls#program-ids-and-accounts) Program IDs & Accounts Light System Program **SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7** Compressed Token Program **cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m** Account Compression Program **compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq** Public State Tree #1 **smt1NamzXdq4AMqS2fS2F1i5KTYPZRhoHgWx38d8WsT** Public Nullifier Queue #1 **nfq1NvQDJ2GEgnS8zt9prAe8rjjpAW1zFkrvZoBR148** Public Address Tree #1 **amt1Ayt45jfbdw5YSo7iz6WZxUmnZsQTYXy82hVwyC2** Public Address Queue #1 **aq1S9z4reTSQAdgWHGD2zDaS39sjGrAxbR31vxJ2F4F** Token Escrow Owner PDA **GXtd2izAiMJPwMEjfgTRH3d7k9mjn4Jq3JrWFv9gySYy** ### [](https://www.zkcompression.com/developers/addresses-and-urls#lookup-tables) Lookup Tables [Lookup tables](https://solana.com/docs/advanced/lookup-tables) reduce your transaction size. We provide pre-initialized lookup tables that cover the Light's program IDs and accounts: Lookup Table #1 (Mainnet) **9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ** Lookup Table #1 (Devnet) **qAJZMgnQJ8G6vA3WRcjD9Jan1wtKkaCFWLWskxJrR5V** [PreviousgetIndexerHealth](https://www.zkcompression.com/developers/json-rpc-methods/getindexerhealth) [NextCreating Airdrops with Compressed Tokens](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens) Last updated 5 months ago Was this helpful? We provide a helper function if you need to extend a custom lookup table. [here](https://www.zkcompression.com/developers/typescript-client#creating-lookup-tables) --- # getCompressionSignaturesForAddress | ZK Compression [PreviousgetCompressionSignaturesForAccount](https://www.zkcompression.com/developers/json-rpc-methods/getcompressionsignaturesforaccount) [NextgetCompressionSignaturesForOwner](https://www.zkcompression.com/developers/json-rpc-methods/getcompressionsignaturesforowner) Last updated 9 months ago Was this helpful? Return the signatures of the transactions that closed or opened a compressed account with the given address. This is a paginated endpoint --- # getMultipleCompressedAccounts | ZK Compression [PreviousgetCompressedAccountsByOwner](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedaccountsbyowner) [NextgetCompressedTokenAccountsByOwner](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedtokenaccountsbyowner) Last updated 9 months ago Was this helpful? Returns multiple compressed accounts with the given addresses or hashes --- # getMultipleNewAddressProofs | ZK Compression [PreviousgetMultipleCompressedAccountProofs](https://www.zkcompression.com/developers/json-rpc-methods/getmultiplecompressedaccountproofs) [NextgetValidityProof](https://www.zkcompression.com/developers/json-rpc-methods/getvalidityproof) Last updated 9 months ago Was this helpful? Returns proofs that the new addresses are not taken already and can be created post https://mainnet.helius-rpc.com?api-key=/ Body idstring · enumRequired An ID to identify the request. Possible values: `test-account` jsonrpcstring · enumRequired The version of the JSON-RPC protocol. Possible values: `2.0` methodstring · enumRequired The name of the method to invoke. Possible values: `getMultipleNewAddressProofs` paramsstring\[\]Required A Solana public key represented as a base58 string. Example: `11111117qkFjr4u54stuNNUR8fRF8dNhaP35yvANs` Responses 200Success application/json Responseobject Show properties 429 Exceeded rate limit. application/json 500 The server encountered an unexpected condition that prevented it from fulfilling the request. application/json post / HTTP HTTPcURLJavaScriptPython Copy POST / HTTP/1.1 Host: mainnet.helius-rpc.com Content-Type: application/json Accept: */* Content-Length: 131 { "id": "test-account", "jsonrpc": "2.0", "method": "getMultipleNewAddressProofs", "params": [\ "11111117qkFjr4u54stuNNUR8fRF8dNhaP35yvANs"\ ] } Test it 200Success Copy { "context": { "slot": 100 }, "value": [\ {\ "address": "11111117qkFjr4u54stuNNUR8fRF8dNhaP35yvANs",\ "higherRangeAddress": "11111117qkFjr4u54stuNNUR8fRF8dNhaP35yvANs",\ "lowElementLeafIndex": 1,\ "lowerRangeAddress": "11111117qkFjr4u54stuNNUR8fRF8dNhaP35yvANs",\ "merkleTree": "11111117qkFjr4u54stuNNUR8fRF8dNhaP35yvANs",\ "nextIndex": 1,\ "proof": [\ "11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP"\ ],\ "root": "11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP",\ "rootSeq": 1\ }\ ] } --- # getLatestCompressionSignatures | ZK Compression [PreviousgetCompressionSignaturesForTokenOwner](https://www.zkcompression.com/developers/json-rpc-methods/getcompressionsignaturesfortokenowner) [NextgetLatestNonVotingSignatures](https://www.zkcompression.com/developers/json-rpc-methods/getlatestnonvotingsignatures) Last updated 9 months ago Was this helpful? Returns the signatures of the latest transactions that used the compression program. This is a paginated endpoint post https://mainnet.helius-rpc.com?api-key=/ Body idstring · enumRequired An ID to identify the request. Possible values: `test-account` jsonrpcstring · enumRequired The version of the JSON-RPC protocol. Possible values: `2.0` methodstring · enumRequired The name of the method to invoke. Possible values: `getLatestCompressionSignatures` paramsobjectRequired Show properties Responses 200Success application/json Responseobject Show properties 429 Exceeded rate limit. application/json 500 The server encountered an unexpected condition that prevented it from fulfilling the request. application/json post / HTTP HTTPcURLJavaScriptPython Copy POST / HTTP/1.1 Host: mainnet.helius-rpc.com Content-Type: application/json Accept: */* Content-Length: 116 { "id": "test-account", "jsonrpc": "2.0", "method": "getLatestCompressionSignatures", "params": { "cursor": "text", "limit": 1 } } Test it 200Success Copy { "context": { "slot": 100 }, "value": { "cursor": "text", "items": [\ {\ "blockTime": 1714081554,\ "signature": "5J8H5sTvEhnGcB4R8K1n7mfoiWUD9RzPVGES7e3WxC7c",\ "slot": 100\ }\ ] } } --- # getCompressionSignaturesForOwner | ZK Compression [PreviousgetCompressionSignaturesForAddress](https://www.zkcompression.com/developers/json-rpc-methods/getcompressionsignaturesforaddress) [NextgetCompressionSignaturesForTokenOwner](https://www.zkcompression.com/developers/json-rpc-methods/getcompressionsignaturesfortokenowner) Last updated 9 months ago Was this helpful? Returns the signatures of the transactions that have modified an owner's compressed accounts. This is a paginated endpoint --- # getTransactionWithCompressionInfo | ZK Compression [PreviousgetCompressedTokenAccountsByDelegate](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedtokenaccountsbydelegate) [NextgetCompressedAccountProof](https://www.zkcompression.com/developers/json-rpc-methods/getcompressedaccountproof) Last updated 9 months ago Was this helpful? Returns the transaction data for the transaction with the given signature along with parsed compression info --- # Using Token-2022 | ZK Compression [PreviousCreating Airdrops with Compressed Tokens](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens) [NextAdd Compressed Token Support to Your Wallet](https://www.zkcompression.com/developers/add-compressed-token-support-to-your-wallet) Last updated 1 month ago Was this helpful? You can compress token-2022 accounts of mints with the following mint-extensions: * MetadataPointer * TokenMetadata * InterestBearingConfig * GroupPointer * GroupMemberPointer * TokenGroup * TokenGroupMember All other extensions are not yet supported. If you require support for other mint-extensions, ! [](https://www.zkcompression.com/developers/using-token-2022#minting-compressing-and-transferring-tokens-with-token-2022-metadata) Minting, compressing, and transferring tokens with Token-2022 Metadata -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- You need the following SDK versions: * `@lightprotocol/stateless.js` ≥ 0.21.0 * `@lightprotocol/compressed-token` ≥ 0.21.0 * `@solana/web3.js` ≥ 1.95.3 Copy import { confirmTx, createRpc } from "@lightprotocol/stateless.js"; import { compress, createTokenPool, transfer, } from "@lightprotocol/compressed-token"; import { getOrCreateAssociatedTokenAccount, mintTo as mintToSpl, TOKEN_2022_PROGRAM_ID, createInitializeMetadataPointerInstruction, createInitializeMintInstruction, ExtensionType, getMintLen, LENGTH_SIZE, TYPE_SIZE, } from "@solana/spl-token"; import { Keypair, sendAndConfirmTransaction, SystemProgram, Transaction, } from "@solana/web3.js"; import { createInitializeInstruction, pack, TokenMetadata, } from "@solana/spl-token-metadata"; import dotenv from "dotenv"; import bs58 from "bs58"; dotenv.config(); // set these values in your .env file const payer = Keypair.fromSecretKey(bs58.decode(process.env.PAYER_KEYPAIR!)); const RPC_ENDPOINT = process.env.RPC_ENDPOINT!; const connection = createRpc(RPC_ENDPOINT); (async () => { const mint = Keypair.generate(); const decimals = 9; const metadata: TokenMetadata = { mint: mint.publicKey, name: "name", symbol: "symbol", uri: "uri", additionalMetadata: [["key", "value"]], }; const mintLen = getMintLen([ExtensionType.MetadataPointer]); const metadataLen = TYPE_SIZE + LENGTH_SIZE + pack(metadata).length; // airdrop to pay gas await confirmTx( connection, await connection.requestAirdrop(payer.publicKey, 1e7) ); const mintLamports = await connection.getMinimumBalanceForRentExemption( mintLen + metadataLen ); const mintTransaction = new Transaction().add( SystemProgram.createAccount({ fromPubkey: payer.publicKey, newAccountPubkey: mint.publicKey, space: mintLen, lamports: mintLamports, programId: TOKEN_2022_PROGRAM_ID, }), createInitializeMetadataPointerInstruction( mint.publicKey, payer.publicKey, mint.publicKey, TOKEN_2022_PROGRAM_ID ), createInitializeMintInstruction( mint.publicKey, decimals, payer.publicKey, null, TOKEN_2022_PROGRAM_ID ), createInitializeInstruction({ programId: TOKEN_2022_PROGRAM_ID, mint: mint.publicKey, metadata: mint.publicKey, name: metadata.name, symbol: metadata.symbol, uri: metadata.uri, mintAuthority: payer.publicKey, updateAuthority: payer.publicKey, }) ); const txId = await sendAndConfirmTransaction(connection, mintTransaction, [\ payer,\ mint,\ ]); console.log(`txId: ${txId}`); // register the mint with the Compressed-Token program const txId2 = await createTokenPool( connection, payer, mint.publicKey, undefined, TOKEN_2022_PROGRAM_ID ); console.log(`register-mint success! txId: ${txId2}`); const ata = await getOrCreateAssociatedTokenAccount( connection, payer, mint.publicKey, payer.publicKey, undefined, undefined, undefined, TOKEN_2022_PROGRAM_ID ); console.log(`ATA: ${ata.address}`); // Mint SPL const mintTxId = await mintToSpl( connection, payer, mint.publicKey, ata.address, payer.publicKey, 1e5, undefined, undefined, TOKEN_2022_PROGRAM_ID ); console.log(`mint-spl success! txId: ${mintTxId}`); const compressedTokenTxId = await compress( connection, payer, mint.publicKey, 1e5, payer, ata.address, payer.publicKey ); console.log(`compressed-token success! txId: ${compressedTokenTxId}`); const transferCompressedTxId = await transfer( connection, payer, mint.publicKey, 1e5, payer, payer.publicKey // self-transfer ); console.log(`transfer-compressed success! txId: ${transferCompressedTxId}`); })(); [let us know](https://t.me/swen_light) --- # getIndexerHealth | ZK Compression [PreviousgetIndexerSlot](https://www.zkcompression.com/developers/json-rpc-methods/getindexerslot) [NextAddresses and URLs](https://www.zkcompression.com/developers/addresses-and-urls) Last updated 9 months ago Was this helpful? Returns an error if the indexer is stale by more than a configurable number of blocks. Otherwise, it returns `ok` post https://mainnet.helius-rpc.com?api-key=/ Body idstring · enumRequired An ID to identify the request. Possible values: `test-account` jsonrpcstring · enumRequired The version of the JSON-RPC protocol. Possible values: `2.0` methodstring · enumRequired The name of the method to invoke. Possible values: `getIndexerHealth` Responses 200Success application/json Responsestring · enum ok if healthy Default: `ok`Possible values: `ok` 429 Exceeded rate limit. application/json 500 The server encountered an unexpected condition that prevented it from fulfilling the request. application/json post / HTTP HTTPcURLJavaScriptPython Copy POST / HTTP/1.1 Host: mainnet.helius-rpc.com Content-Type: application/json Accept: */* Content-Length: 65 { "id": "test-account", "jsonrpc": "2.0", "method": "getIndexerHealth" } Test it 200Success Copy ok --- # getLatestNonVotingSignatures | ZK Compression [PreviousgetLatestCompressionSignatures](https://www.zkcompression.com/developers/json-rpc-methods/getlatestcompressionsignatures) [NextgetIndexerSlot](https://www.zkcompression.com/developers/json-rpc-methods/getindexerslot) Last updated 9 months ago Was this helpful? Returns the signatures of the latest transactions that are not voting transactions post https://mainnet.helius-rpc.com?api-key=/ Body idstring · enumRequired An ID to identify the request. Possible values: `test-account` jsonrpcstring · enumRequired The version of the JSON-RPC protocol. Possible values: `2.0` methodstring · enumRequired The name of the method to invoke. Possible values: `getLatestNonVotingSignatures` paramsobjectRequired Show properties Responses 200Success application/json Responseobject Show properties 429 Exceeded rate limit. application/json 500 The server encountered an unexpected condition that prevented it from fulfilling the request. application/json post / HTTP HTTPcURLJavaScriptPython Copy POST / HTTP/1.1 Host: mainnet.helius-rpc.com Content-Type: application/json Accept: */* Content-Length: 114 { "id": "test-account", "jsonrpc": "2.0", "method": "getLatestNonVotingSignatures", "params": { "cursor": "text", "limit": 1 } } Test it 200Success Copy { "context": { "slot": 100 }, "value": { "items": [\ {\ "blockTime": 1714081554,\ "error": "text",\ "signature": "5J8H5sTvEhnGcB4R8K1n7mfoiWUD9RzPVGES7e3WxC7c",\ "slot": 100\ }\ ] } } --- # getIndexerSlot | ZK Compression [PreviousgetLatestNonVotingSignatures](https://www.zkcompression.com/developers/json-rpc-methods/getlatestnonvotingsignatures) [NextgetIndexerHealth](https://www.zkcompression.com/developers/json-rpc-methods/getindexerhealth) Last updated 9 months ago Was this helpful? Returns the slot of the last block indexed by the indexer post https://mainnet.helius-rpc.com?api-key=/ Body idstring · enumRequired An ID to identify the request. Possible values: `test-account` jsonrpcstring · enumRequired The version of the JSON-RPC protocol. Possible values: `2.0` methodstring · enumRequired The name of the method to invoke. Possible values: `getIndexerSlot` Responses 200Success application/json ResponseintegerDefault: `100`Example: `100` 429 Exceeded rate limit. application/json 500 The server encountered an unexpected condition that prevented it from fulfilling the request. application/json post / HTTP HTTPcURLJavaScriptPython Copy POST / HTTP/1.1 Host: mainnet.helius-rpc.com Content-Type: application/json Accept: */* Content-Length: 63 { "id": "test-account", "jsonrpc": "2.0", "method": "getIndexerSlot" } Test it 200Success Copy 100 --- # getValidityProof | ZK Compression [PreviousgetMultipleNewAddressProofs](https://www.zkcompression.com/developers/json-rpc-methods/getmultiplenewaddressproofs) [NextgetCompressionSignaturesForAccount](https://www.zkcompression.com/developers/json-rpc-methods/getcompressionsignaturesforaccount) Last updated 2 months ago Was this helpful? Returns a single ZK Proof used by the compression program to verify that the given accounts are valid and that the new addresses can be created * Proof limits per request are: * `hashes`: 1, 2, 3, 4, or 8 * `newAddressesWithTrees` : 1, 2 * The `newAddresses` param field is supported but deprecated. Please use `newAddressesWithTrees`instead. post https://mainnet.helius-rpc.com?api-key=/ Body idstring · enumRequired An ID to identify the request. Possible values: `test-account` jsonrpcstring · enumRequired The version of the JSON-RPC protocol. Possible values: `2.0` methodstring · enumRequired The name of the method to invoke. Possible values: `getValidityProof` paramsobjectRequired Show properties Responses 200Success application/json Responseobject Show properties 429 Exceeded rate limit. application/json 500 The server encountered an unexpected condition that prevented it from fulfilling the request. application/json post / HTTP HTTPcURLJavaScriptPython Copy POST / HTTP/1.1 Host: mainnet.helius-rpc.com Content-Type: application/json Accept: */* Content-Length: 264 { "id": "test-account", "jsonrpc": "2.0", "method": "getValidityProof", "params": { "hashes": [\ "11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP"\ ], "newAddressesWithTrees": [\ {\ "address": "11111118eRTi4fUVRoeYEeeTyL4DPAwxatvWT5q1Z",\ "tree": "11111118eRTi4fUVRoeYEeeTyL4DPAwxatvWT5q1Z"\ }\ ] } } Test it 200Success Copy { "context": { "slot": 100 }, "value": { "compressedProof": { "a": "binary", "b": "binary", "c": "binary" }, "leafIndices": [\ 1\ ], "leaves": [\ "text"\ ], "merkleTrees": [\ "text"\ ], "rootIndices": [\ 1\ ], "roots": [\ "text"\ ] } } --- # Create programs with the program-template | ZK Compression We've created a **program template** that you can use to bootstrap your program. _Note the program-template as well as the light-sdk and proc macros are experimental convenience helpers, and their APIs are subject to change._ ### [](https://www.zkcompression.com/developers/create-programs-with-the-program-template#id-1.-install-the-cli) 1\. Install the CLI Package Manager Command npm Yarn ### [](https://www.zkcompression.com/developers/create-programs-with-the-program-template#id-2.-initialize-your-program) 2\. **Initialize your program** Requires version **v0.15.1** or higher. Copy light init testprogram This initializes an anchor program with a basic counter program template using compressed accounts. Now, run: Copy anchor build Copy cargo test-sbf ### [](https://www.zkcompression.com/developers/create-programs-with-the-program-template#common-errors) Common Errors `'assert.h' file not found` - during compilation.[](https://www.zkcompression.com/developers/create-programs-with-the-program-template#assert.h-file-not-found-during-compilation) Copy Fix: In your terminal, run: 1. export CC=$(xcrun -find clang) 2. export SDKROOT=$(xcrun --show-sdk-path) 3. cargo clean 4. anchor build Example log: The following warnings were emitted during compilation: warning: [email protected]: In file included from c/blake3_neon.c:1: warning: [email protected]: c/blake3_impl.h:4:10: fatal error: 'assert.h' file not found warning: [email protected]: 4 | #include warning: [email protected]: | ^~~~~~~~~~ warning: [email protected]: 1 error generated. error: failed to run custom build command for `blake3 v1.5.1` Caused by: process didn't exit successfully: `/Users/you/testprogram/target/release/build/blake3-ac41d29c2eabe052/build-script-build` (exit status: 1) --- stdout cargo:rerun-if-env-changed=CARGO_FEATURE_PURE cargo:rerun-if-env-changed=CARGO_FEATURE_NO_NEON cargo:rerun-if-env-changed=CARGO_FEATURE_NEON cargo:rerun-if-env-changed=CARGO_FEATURE_NEON cargo:rerun-if-env-changed=CARGO_FEATURE_NO_NEON cargo:rerun-if-env-changed=CARGO_FEATURE_PURE cargo:rustc-cfg=blake3_neon OUT_DIR = Some(/Users/you/testprogram/target/release/build/blake3-735a4c71d985df30/out) TARGET = Some(aarch64-apple-darwin) OPT_LEVEL = Some(3) HOST = Some(aarch64-apple-darwin) cargo:rerun-if-env-changed=CC_aarch64-apple-darwin CC_aarch64-apple-darwin = None cargo:rerun-if-env-changed=CC_aarch64_apple_darwin CC_aarch64_apple_darwin = None cargo:rerun-if-env-changed=HOST_CC HOST_CC = None cargo:rerun-if-env-changed=CC CC = Some(/Users/you/.local/share/solana/install/releases/1.18.22/solana-release/bin/sdk/sbf/dependencies/platform-tools/llvm/bin/clang) RUSTC_WRAPPER = None cargo:rerun-if-env-changed=CC_ENABLE_DEBUG_OUTPUT cargo:rerun-if-env-changed=CRATE_CC_NO_DEFAULTS CRATE_CC_NO_DEFAULTS = None DEBUG = Some(false) cargo:rerun-if-env-changed=MACOSX_DEPLOYMENT_TARGET MACOSX_DEPLOYMENT_TARGET = None cargo:rerun-if-env-changed=CFLAGS_aarch64-apple-darwin CFLAGS_aarch64-apple-darwin = None cargo:rerun-if-env-changed=CFLAGS_aarch64_apple_darwin CFLAGS_aarch64_apple_darwin = None cargo:rerun-if-env-changed=HOST_CFLAGS HOST_CFLAGS = None cargo:rerun-if-env-changed=CFLAGS CFLAGS = None cargo:warning=In file included from c/blake3_neon.c:1: cargo:warning=c/blake3_impl.h:4:10: fatal error: 'assert.h' file not found cargo:warning= 4 | #include cargo:warning= | ^~~~~~~~~~ cargo:warning=1 error generated. --- stderr error occurred: Command env -u IPHONEOS_DEPLOYMENT_TARGET "/Users/you/.local/share/solana/install/releases/1.18.22/solana-release/bin/sdk/sbf/dependencies/platform-tools/llvm/bin/clang" "-O3" "-ffunction-sections" "-fdata-sections" "-fPIC" "--target=arm64-apple-darwin" "-mmacosx-version-min=14.4" "-Wall" "-Wextra" "-std=c11" "-o" "/Users/you/testprogram/target/release/build/blake3-735a4c71d985df30/out/db3b6bfb95261072-blake3_neon.o" "-c" "c/blake3_neon.c" with args clang did not execute successfully (status code exit status: 1). [](https://www.zkcompression.com/developers/create-programs-with-the-program-template#support) Support ----------------------------------------------------------------------------------------------------------- [PreviousAdd Compressed Token Support to Your Wallet](https://www.zkcompression.com/developers/add-compressed-token-support-to-your-wallet) [NextRun a Node](https://www.zkcompression.com/node-operators/run-a-node) Last updated 8 months ago Was this helpful? For additional support or questions, please refer to our or contact or on Telegram or via Copy npm install -g @lightprotocol/zk-compression-cli Copy yarn global add @lightprotocol/zk-compression-cli [documentation](https://www.zkcompression.com/) [Swen](https://t.me/swen_light) [Mert](https://t.me/mert_helius) [email](https://www.zkcompression.com/cdn-cgi/l/email-protection#d3b5a1bab6bdb7a093bfbab4bba7a3a1bca7bcb0bcbffdb0bcbe) --- # Security | ZK Compression [PreviousRun a Node](https://www.zkcompression.com/node-operators/run-a-node) [NextPrivacy Policy](https://www.zkcompression.com/resources/privacy-policy) Last updated 2 months ago Was this helpful? ### [](https://www.zkcompression.com/resources/security#bug-bounty) Bug Bounty Light Protocol is hosting a . ### [](https://www.zkcompression.com/resources/security#security-audits) Security Audits The Light protocol on-chain programs were audited by independent security firms Neodyme, OtterSec, Accretion, and Zellic. * (January '25) * (September '24) * (August '24) * (July '24) A complete list of 3rd party audits can be found . ### [](https://www.zkcompression.com/resources/security#groth16-circuit-security) Groth16 Circuit Security The ZK Compression circuit was formally verified by Reilabs. See the report . Information about the Trusted Setup Ceremony for the groth16 circuits is . **For additional information on Light Protocol's security policy, read** **.** [bug bounty program](https://immunefi.com/bug-bounty/light-protocol/information/) [Accretion audit report](https://github.com/Lightprotocol/light-protocol/blob/main/audits/accretion_v1_update_audit.pdf) [Zellic audit report](https://github.com/Lightprotocol/light-protocol/blob/main/audits/zellic_v1_audit.pdf) [Neodyme audit report](https://github.com/Lightprotocol/light-protocol/blob/main/audits/neodyme_v1_audit.pdf) [OtterSec audit report](https://github.com/Lightprotocol/light-protocol/blob/main/audits/ottersec_v1_audit.pdf) [here](https://github.com/Lightprotocol/light-protocol/tree/main/audits) [here](https://github.com/Lightprotocol/light-protocol/blob/main/audits/reilabs_circuits_formal_verification_report.pdf) [here](https://github.com/Lightprotocol/gnark-mt-setup/blob/main/README.md) [**here**](https://github.com/Lightprotocol/light-protocol/blob/main/SECURITY.md) --- # Add Compressed Token Support to Your Wallet | ZK Compression The following page describes how to add **compressed token** support to your wallet application. _Key benefits of compressed tokens:_ * Up to **5000x** cheaper than uncompressed accounts * Compatible with existing programs via atomic compression and decompression between SPL <> Compressed tokens [](https://www.zkcompression.com/developers/add-compressed-token-support-to-your-wallet#integration-steps) Integration Steps --------------------------------------------------------------------------------------------------------------------------------- ### [](https://www.zkcompression.com/developers/add-compressed-token-support-to-your-wallet#id-1.-install-the-sdk) 1\. Install the SDK Package Manager Command npm Yarn ### [](https://www.zkcompression.com/developers/add-compressed-token-support-to-your-wallet#id-2.-create-an-rpc-connection) 2\. **Create an RPC Connection** Copy import { Rpc, createRpc, } from "@lightprotocol/stateless.js"; const RPC_ENDPOINT = "https://devnet.helius-rpc.com?api-key="; const connection: Rpc = createRpc(RPC_ENDPOINT) **Using Localnet**[](https://www.zkcompression.com/developers/add-compressed-token-support-to-your-wallet#using-localnet) Copy # Install the development CLI npm install @lightprotocol/zk-compression-cli Copy # Start a local test validator light test-validator Copy 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(); ### [](https://www.zkcompression.com/developers/add-compressed-token-support-to-your-wallet#id-3.-display-compressed-token-balances) 3\. Display Compressed Token Balances Copy import { Rpc, createRpc } from '@lightprotocol/stateless.js'; import { PublicKey } from '@solana/web3.js'; const RPC_ENDPOINT = 'https://devnet.helius-rpc.com?api-key='; const connection: Rpc = createRpc(RPC_ENDPOINT); const publicKey = new PublicKey('CLEuMG7pzJX9xAuKCFzBP154uiG1GaNo4Fq7x6KAcAfG'); (async () => { // Returns balance for owner per mint // Can optionally apply filter: {mint, limit, cursor} const balances = await connection.getCompressedTokenBalancesByOwnerV2(publicKey); console.log(balances); })(); ### [](https://www.zkcompression.com/developers/add-compressed-token-support-to-your-wallet#id-4.-get-compression-signature-history-by-owner) 4\. Get Compression Signature History By Owner Copy import { Rpc, createRpc } from '@lightprotocol/stateless.js'; import { PublicKey } from '@solana/web3.js'; const RPC_ENDPOINT = 'https://devnet.helius-rpc.com?api-key='; const connection: Rpc = createRpc(RPC_ENDPOINT); const publicKey = new PublicKey('CLEuMG7pzJX9xAuKCFzBP154uiG1GaNo4Fq7x6KAcAfG'); (async () => { // 1. Fetch signatures for the user // // Returns confirmed signatures for compression transactions involving the // specified account owner const signatures = await connection.getCompressionSignaturesForOwner(publicKey); console.log(signatures); // 2. Fetch transactions with compression info // // Returns pre- and post-compressed token balances grouped by owner const parsedTransaction = await connection.getTransactionWithCompressionInfo(signatures[0].signature) console.log(parsedTransaction) })(); **Full JSON RPC API:** ### [](https://www.zkcompression.com/developers/add-compressed-token-support-to-your-wallet#id-5.-send-compressed-tokens) 5\. Send Compressed Tokens Setup Test Mint[](https://www.zkcompression.com/developers/add-compressed-token-support-to-your-wallet#setup-test-mint) Copy import { Keypair } from "@solana/web3.js"; import { Rpc, confirmTx, createRpc } from '@lightprotocol/stateless.js'; import { createMint, mintTo } from '@lightprotocol/compressed-token'; // Set these values... const RPC_ENDPOINT = ''; const connection: Rpc = createRpc(RPC_ENDPOINT); const PAYER = Keypair.generate(); const PUBLIC_KEY = PAYER.publicKey; const MINT_KEYPAIR = Keypair.generate(); const RECIPIENT_PUBLIC_KEY = Keypair.generate().publicKey.toBase58(); /// Airdrop tokens to PAYER beforehand. (async() => { /// Create and register compressed-token mint const { mint, transactionSignature } = await createMint( connection, PAYER, PAYER.publicKey, 9, PAYER, ); console.log(`create-mint success! txId: ${transactionSignature}`); /// Mint compressed tokens const mintToTxId = await mintTo( connection, PAYER, mint, PAYER.publicKey, PAYER, 1e9, ); console.log(`mint-to success! txId: ${mintToTxId}`); })(); Copy import { Rpc, createRpc, bn, dedupeSigner, sendAndConfirmTx, buildAndSignTx, } from "@lightprotocol/stateless.js"; import { CompressedTokenProgram, selectMinCompressedTokenAccountsForTransfer, } from "@lightprotocol/compressed-token"; import { ComputeBudgetProgram, Keypair } from "@solana/web3.js"; // 0. Set these values const RPC_ENDPOINT = "https://mainnet.helius-rpc.com?api-key="; const mint = ; const payer = ; const owner = payer; const recipient = Keypair.generate(); const amount = bn(1e8); const connection: Rpc = createRpc(RPC_ENDPOINT); (async () => { // 1. Fetch latest token account state const compressedTokenAccounts = await connection.getCompressedTokenAccountsByOwner(owner.publicKey, { mint, }); // 2. Select accounts to transfer from based on the transfer amount const [inputAccounts] = selectMinCompressedTokenAccountsForTransfer( compressedTokenAccounts.items, amount ); // 3. Fetch recent validity proof const proof = await connection.getValidityProof( inputAccounts.map((account) => account.compressedAccount.hash) ); // 4. Create transfer instruction const ix = await CompressedTokenProgram.transfer({ payer: payer.publicKey, inputCompressedTokenAccounts: inputAccounts, toAddress: recipient.publicKey, amount, recentInputStateRootIndices: proof.rootIndices, recentValidityProof: proof.compressedProof, }); // 8. Sign, send, and confirm... const { blockhash } = await connection.getLatestBlockhash(); const additionalSigners = dedupeSigner(payer, [owner]); const signedTx = buildAndSignTx( [ComputeBudgetProgram.setComputeUnitLimit({ units: 300_000 }), ix], payer, blockhash, additionalSigners ); return await sendAndConfirmTx(connection, signedTx); })(); ### [](https://www.zkcompression.com/developers/add-compressed-token-support-to-your-wallet#advanced-integration) Advanced Integration **Decompress SPL Tokens**[](https://www.zkcompression.com/developers/add-compressed-token-support-to-your-wallet#decompress-spl-tokens) Copy import { bn, buildAndSignTx, sendAndConfirmTx, dedupeSigner, Rpc, createRpc, } from "@lightprotocol/stateless.js"; import { ComputeBudgetProgram } from "@solana/web3.js"; import { CompressedTokenProgram, getTokenPoolInfos, selectMinCompressedTokenAccountsForTransfer, selectTokenPoolInfosForDecompression, } from "@lightprotocol/compressed-token"; // 0. Set these values. const connection: Rpc = createRpc("https://mainnet.helius-rpc.com?api-key=";); const payer = PAYER_KEYPAIR; const owner = PAYER_KEYPAIR; const mint = MINT_ADDRESS; const amount = 1e5; (async () => { // 1. Fetch compressed token accounts const compressedTokenAccounts = await connection.getCompressedTokenAccountsByOwner(owner.publicKey, { mint, }); // 2. Select const [inputAccounts] = selectMinCompressedTokenAccountsForTransfer( compressedTokenAccounts.items, bn(amount) ); // 3. Fetch validity proof const proof = await connection.getValidityProof( inputAccounts.map((account) => account.compressedAccount.hash) ); // 4. Fetch & Select tokenPoolInfos const tokenPoolInfos = await getTokenPoolInfos(connection, mint); const selectedTokenPoolInfos = selectTokenPoolInfosForDecompression( tokenPoolInfos, amount ); // 5. Build instruction const ix = await CompressedTokenProgram.decompress({ payer: payer.publicKey, inputCompressedTokenAccounts: inputAccounts, toAddress: owner.publicKey, amount, tokenPoolInfos: selectedTokenPoolInfos, recentInputStateRootIndices: proof.rootIndices, recentValidityProof: proof.compressedProof, }); // 6. Sign, send, and confirm. // Example with keypair: const { blockhash } = await connection.getLatestBlockhash(); const additionalSigners = dedupeSigner(payer, [owner]); const signedTx = buildAndSignTx( [ComputeBudgetProgram.setComputeUnitLimit({ units: 300_000 }), ix], payer, blockhash, additionalSigners ); return await sendAndConfirmTx(connection, signedTx); })(); **Compress SPL Tokens**[](https://www.zkcompression.com/developers/add-compressed-token-support-to-your-wallet#compress-spl-tokens) Copy import { buildAndSignTx, sendAndConfirmTx, Rpc, createRpc, selectStateTreeInfo, } from "@lightprotocol/stateless.js"; import { ComputeBudgetProgram } from "@solana/web3.js"; import { CompressedTokenProgram, getTokenPoolInfos, selectTokenPoolInfo, } from "@lightprotocol/compressed-token"; import { getOrCreateAssociatedTokenAccount } from "@solana/spl-token"; // 0. Set these values. const connection: Rpc = createRpc( "https://mainnet.helius-rpc.com?api-key=" ); const payer = ; const mint = ; const amount = 1e5; (async () => { // 1. Get user ATA const sourceTokenAccount = await getOrCreateAssociatedTokenAccount( connection, payer, mint, payer.publicKey ); // 2. Fetch & Select treeInfos const treeInfos = await connection.getStateTreeInfos(); const treeInfo = selectStateTreeInfo(treeInfos); // 3. Fetch & Select tokenPoolInfo const tokenPoolInfos = await getTokenPoolInfos(connection, mint); const tokenPoolInfo = selectTokenPoolInfo(tokenPoolInfos); // 4. Build compress instruction const compressInstruction = await CompressedTokenProgram.compress({ payer: payer.publicKey, owner: payer.publicKey, source: sourceTokenAccount.address, toAddress: payer.publicKey, // to self. amount, mint, outputStateTreeInfo: treeInfo, tokenPoolInfo, }); // 5. Sign and send tx // Example with Keypair: const { blockhash } = await connection.getLatestBlockhash(); const tx = buildAndSignTx( [\ ComputeBudgetProgram.setComputeUnitLimit({ units: 300_000 }),\ compressInstruction,\ ], payer, blockhash, [payer] ); await sendAndConfirmTx(connection, tx); })(); [](https://www.zkcompression.com/developers/add-compressed-token-support-to-your-wallet#best-practices) Best Practices --------------------------------------------------------------------------------------------------------------------------- * **Clear UI Indicators —** Provide clear visual distinctions between compressed and uncompressed SPL tokens * **Transaction History** — Provide detailed transaction histories for compressed tokens * **Decompression and Compression** — Provide a clear path for users to convert between compressed and uncompressed tokens when needed [](https://www.zkcompression.com/developers/add-compressed-token-support-to-your-wallet#support) Support ------------------------------------------------------------------------------------------------------------- [PreviousUsing Token-2022](https://www.zkcompression.com/developers/using-token-2022) [NextCreate programs with the program-template](https://www.zkcompression.com/developers/create-programs-with-the-program-template) Last updated 1 month ago Was this helpful? For additional support or questions, please refer to our or contact or on Telegram or via . Copy npm install --save \ @lightprotocol/stateless.js \ @lightprotocol/compressed-token \ @solana/web3.js Copy yarn add \ @lightprotocol/stateless.js \ @lightprotocol/compressed-token \ @solana/web3.js [JSON RPC Methods](https://www.zkcompression.com/developers/json-rpc-methods) [documentation](https://www.zkcompression.com/) [Swen](https://t.me/swen_light) [Mert](https://t.me/mert_helius) [email](https://www.zkcompression.com/cdn-cgi/l/email-protection#781e0a111d161c0b3814111f100c080a170c171b1714561b1715) --- # Run a Node | ZK Compression [PreviousCreate programs with the program-template](https://www.zkcompression.com/developers/create-programs-with-the-program-template) [NextSecurity](https://www.zkcompression.com/resources/security) Last updated 4 months ago Was this helpful? [](https://www.zkcompression.com/node-operators/run-a-node#running-a-node-for-local-development) Running a Node for Local Development ------------------------------------------------------------------------------------------------------------------------------------------ For local development, the [ZK Compression CLI](https://github.com/Lightprotocol/light-protocol/blob/main/cli/) `test-validator` command starts a single-node Solana cluster with all relevant nodes (Photon RPC and Prover), system programs, accounts, and runtime features: Copy light test-validator To connect to public networks (i.e., Devnet, Mainnet-Beta), you can either work with an RPC infrastructure provider that supports ZK Compression, such as [Helius Labs](https://helius.xyz/) , or run your own nodes: There are three different types of nodes: * [Photon RPC nodes](https://www.zkcompression.com/node-operators/run-a-node#photon-rpc-node) * [Prover nodes](https://www.zkcompression.com/node-operators/run-a-node#prover-node) * [Light forester nodes](https://www.zkcompression.com/node-operators/run-a-node#forester-node) _Becoming an operator for any node type is permissionless_ [](https://www.zkcompression.com/node-operators/run-a-node#photon-rpc-node) Photon RPC Node ------------------------------------------------------------------------------------------------ RPC nodes index the Light Protocol programs, enabling clients to read and build transactions interacting with compressed state. The canonical ZK Compression indexer is named Photon. It can be run locally and requires minimal setup, which must be pointed to an existing Solana RPC. See the Github [repo](https://github.com/helius-labs/photon) for more info: [](https://www.zkcompression.com/node-operators/run-a-node#prover-node) Prover Node ---------------------------------------------------------------------------------------- Provers generate validity proofs for state inclusion on behalf of app developers **Prover nodes** can be operated either stand-alone or with an RPC node: in its default configuration, the Photon RPC node implementation by [Helius Labs](https://github.com/helius-labs/photon) bundles a Prover node. The [ZK Compression RPC API](https://docs.lightprotocol.com/developers/json-rpc-methods) specification supports proof generation via the `getValidityProof` endpoint, making it easy to serve proofs using regular RPC methods via the same port. Please refer to the Github repo for more info: [](https://www.zkcompression.com/node-operators/run-a-node#light-forester-node) Light Forester Node -------------------------------------------------------------------------------------------------------- Developers may choose to have their program-owned state trees serviced by a network of Light Forester nodes. These nodes manage the creation, rollover, and updating of shared and program-owned state trees. [GitHub - helius-labs/photonGitHub](https://github.com/helius-labs/photon) [light-protocol/light-prover at main · Lightprotocol/light-protocolGitHub](https://github.com/Lightprotocol/light-protocol/tree/main/light-prover) [light-protocol/forester at main · Lightprotocol/light-protocolGitHub](https://github.com/Lightprotocol/light-protocol/tree/main/forester) ![Logo](https://www.zkcompression.com/~gitbook/image?url=https%3A%2F%2Fgithub.com%2Ffluidicon.png&width=20&dpr=4&quality=100&sign=77d83f0c&sv=2) ![Logo](https://www.zkcompression.com/~gitbook/image?url=https%3A%2F%2Fgithub.com%2Ffluidicon.png&width=20&dpr=4&quality=100&sign=77d83f0c&sv=2) ![Logo](https://www.zkcompression.com/~gitbook/image?url=https%3A%2F%2Fgithub.com%2Ffluidicon.png&width=20&dpr=4&quality=100&sign=77d83f0c&sv=2) --- # Privacy Policy | ZK Compression [PreviousSecurity](https://www.zkcompression.com/resources/security) Last updated 8 months ago Was this helpful? 1\. PURPOSE OF THIS DOCUMENT 1.1. This privacy policy ("Privacy Policy") describes how Light Protocol Labs ("Light Protocol," "we," "us," or "our") collects, uses, and shares information about you. This Privacy Policy applies whenever you use (the "Website" or “Service”), contact our support team, interact with us on social media, or engage with us in any other manner. 1.2. We may update this Privacy Policy from time to time and therefore encourage you to review this Privacy Policy frequently. If any changes are made, we will update the revision date at the top of this policy, and in certain cases, we may provide additional notice (such as posting a notice on our Website or sending a notification). 1.3. For any matters, relating to data protection you may contact in writing by e-mail . 2\. CONTENTS COLLECTING OF INFORMATION USE OF INFORMATION RETENTION OF INFORMATION YOUR RIGHTS DISCLOSURE OF DATA TRANSFERS OF INFORMATION DATA SECURITY AND LIABILITY MINORS PRIVACY LINKS TO OTHER WEBSITES YOUR CALIFORNIA PRIVACY RIGHTS ADDITIONAL DISCLOSURES FOR INDIVIDUALS IN EUROPE CONTACT 3\. COLLECTING OF INFORMATION 3.1. We collect personal information you provide directly to us. 3.2. We collect data about how you access and interact with our Website including information about the device and network you use, such as your hardware model, operating system version, browser type, IP address, mobile network, and unique device identifiers. Additionally, we track your activity on the Website, such as access times, pages viewed, links clicked, and the page that directed you to our Website. 3.3. When accessing the Website via a mobile device, we may also gather information like your device ID, mobile browser type, and operating system. Usage data is collected automatically and includes diagnostic details such as the time spent on each page and other related metrics. 3.4. With your device’s permissions, we may collect precise location data. You can disable the collection of this information at any time by adjusting your device settings. 3.5. We use cookies and similar tracking technologies to gather information about your usage of our Website. Cookies are small data files stored on your device that help us enhance your experience, track popular features, and monitor visits. You may instruct Your browser to refuse all Cookies or to indicate when a Cookie is being sent. If you refuse Cookies, you may not be able to use some parts of our Service. 4\. USE OF INFORMATION 4.1. We use the information collected to provide, maintain, and improve our products, services, and Website. Additionally, we use the data to personalize your experience, respond to customer inquiries, and provide technical notices, security alerts, and support messages. 4.2. Our use of the information extends to: 4.2.1. Monitoring and analyzing trends, usage, and activities related to our Website. 4.2.2. Detecting, investigating, and preventing fraudulent, illegal, or malicious activity to protect the rights and property of our company and others. 4.2.3. Debugging and identifying errors in our Website. 4.2.4. Fulfilling legal and financial obligations. 4.2.5. We may also use the information for additional purposes described to you at the time the data was collected or for purposes like data analysis, identifying trends, and improving our services. 5\. RETENTION OF INFORMATION 5.1. We will retain your information only as long as necessary for the purposes outlined in this Privacy Policy and ay retain Usage Data for security improvements or legal obligations. 5.2. We expect to delete your information (at the latest) once there is no longer any legal or regulatory requirement or legitimate business purpose. 6\. YOUR RIGHTS You have certain data protection rights, including the right to: 6.1. request access to, update, or delete your personal data, and manage your information directly within the Service. 6.2. to correct incomplete or inaccurate data and request the restriction of processing in certain situations. 6.3. to obtain information on how and why your personal data is processed. 6.4. request that we stop processing your personal data and withdraw consent to direct marketing at any time. 6.5. the right to be notified of any data breach that may affect your rights and freedoms. 6.6. request the deletion of your personal data in specific circumstances, such as when it's no longer necessary for the original purpose (right to be forgotten). 7\. DISCLOSURE OF DATA 7.1. We may disclose your Data: 7.1.1. in connection with business transactions. 7.1.2. to comply with legal obligations, if we believe that disclosure is in accordance with, or required by, any applicable law or legal process, including lawful requests by public authorities to meet national security or law enforcement requirements 7.1.3. if we believe that your actions are inconsistent with our user agreements or policies, if we believe that you have violated the law, or if we believe it is necessary to protect the rights, property, and safety of Light Protocol, our users, the public, or others. 7.1.4. to protect the rights, property, or safety of the Company, Service, or users. 8\. TRANSFERS OF INFORMATION 8.1. Your information, including Personal Data, is processed at the Company's operating offices and in any other places where the parties involved in the processing are located. It means that this information may be transferred to — and maintained on — computers located outside of Your state, province, country or other governmental jurisdiction where the data protection laws may differ than those from Your jurisdiction 8.2. Your consent to this Privacy Policy followed by your submission of such information represents your agreement to that transfer 8.3. The Company will take all steps reasonably necessary to ensure that your data is treated securely and in accordance with this Privacy Policy and no transfer of your Personal Data will take place to an organization or a country unless there are adequate controls in place including the security of your data and other personal information. 9\. DATA SECURITY AND LIABILITY 9.1. We implement robust technical and organizational measures to safeguard your personal data from unauthorized access, manipulation, loss, or exposure. These security protocols are regularly updated and enhanced in line with evolving technological standards. 9.2. Please be aware that transmitting data over the internet (e.g., through email communications) is not always completely secure, and we cannot be held responsible for any data shared with us via these methods. While we strive to protect your information, absolute security cannot be guaranteed. 9.3. This privacy policy does not extend to third-party websites or any external links provided on our platform. We disclaim any responsibility or liability for the content or data protection practices of third-party websites. 10\. MINORS PRIVACY 10.1. Our Service does not address anyone under 18, and we do not knowingly collect information from minors. 10.2. If you are a parent and aware that your minors has provided Personal Data, please contact Us. 10.3. If We become aware that We have collected Personal Data from anyone under the age of 18 without verification of parental consent, We take steps to remove that information from Our servers. 11\. LINKS TO OTHER WEBSITES 11.1. Our Service may contain links to third-party websites that are not operated by us. 11.2. We advise you to review the Privacy Policy of every site you visit. We have no control over and no responsibility for the content, privacy policies or practices of any third party sites or services. 12\. YOUR CALIFORNIA PRIVACY RIGHTS 12.1. This section applies to you, if you are a California Resident. 12.2. The California Consumer Privacy Act or "CCPA" (California Consumer Privacy Act of 2018) affords consumers residing in California additional rights with respect to their personal information. 12.4. Light Protocol does not sell your personal information. 12.5. We will not discriminate against you if you exercise your rights under the CCPA. 13\. ADDITIONAL DISCLOSURES FOR INDIVIDUALS IN EUROPE 13.1. If you are located in the European Economic Area ("EEA"), the United Kingdom, or Switzerland, you have certain rights and protections under the law regarding the processing of your personal data, and this section applies to you. 13.2. Legal Basis for Processing 13.2.1. When we process your personal data, we will do so in reliance on the following lawful bases: To perform our responsibilities under our contract with you (e.g., processing payments for and providing the products and services you requested). 13.2.2. When we have a legitimate interest in processing your personal data to operate our business or protect our interests (e.g., to provide, maintain, and improve our products and services, conduct data analytics, and communicate with you). 13.2.3. To comply with our legal obligations (e.g., to maintain a record of your consents and track those who have opted out of communications). 13.2.4. When we have your consent to do so (e.g., when you opt in to receive communications from us). 13.2.5. When consent is the legal basis for our processing your personal data, you may withdraw such consent at any time. 13.3. DATA RETENTION We store other personal data for as long as necessary to carry out the purposes for which we originally collected it and for other legitimate business purposes, including to meet our legal, regulatory, or other compliance obligations. 13.4. DATA SUBJECT REQUESTS 13.5. QUESTIONS OR COMPLAINTS Where we are not able to rectify a concern about our processing of personal data you have the right to lodge a complaint with the data protection authority of your place of residence. You can contact your Data Protection Authority using your respective link below: 14\. CONTACT 12.3. You have the right to inform you of (i) the categories of personal information we have collected about you over the past 12 months; (ii) the specific pieces of personal information we collect, use, and disclose about you; (iii) the categories of sources from which we collected your personal information; (iv) The categories of third parties to whom your personal information was disclosed; (v) the purposes for collecting your personal information; (vi) request deletion of your personal information, and (vii) not be discriminated against for exercising these rights. You may make these requests by contacting us at . Please note that these rights may be subject to limitations as outlined by applicable laws. In certain cases, we may need to deny your request in order to comply with our legal obligations or protect our rights. Subject to certain limitations, you have the right to request access to the personal data we hold about you and to receive your data in a portable format, the right to ask that your personal data be corrected or erased, and the right to object to, or request that we restrict, certain processing. If you would like to exercise any of these rights, please contact us at . · EEA residents: · UK residents: · Switzerland residents: If you have any questions about this Privacy Policy, You can contact us at email referencing “Data Protection Enquiry". [https://www.zkcompression.com](https://www.zkcompression.com/) [\[email protected\]](https://www.zkcompression.com/cdn-cgi/l/email-protection#82e4f0ebe7ece6f1c2eeebe5eaf6f2f0edf6ede1edeeace1edef) [\[email protected\]](https://www.zkcompression.com/cdn-cgi/l/email-protection#0264706b676c6671426e6b656a7672706d766d616d6e2c616d6f) [\[email protected\]](https://www.zkcompression.com/cdn-cgi/l/email-protection#82e4f0ebe7ece6f1c2eeebe5eaf6f2f0edf6ede1edeeace1edef) [https://edpb.europa.eu/about-edpb/board/members\_en](https://edpb.europa.eu/about-edpb/board/members_en) [https://ico.org.uk/global/contact-us/](https://ico.org.uk/global/contact-us/) [https://www.edoeb.admin.ch/edoeb/en/home/the-fdpic/contact.html](https://www.edoeb.admin.ch/edoeb/en/home/the-fdpic/contact.html) [\[email protected\]](https://www.zkcompression.com/cdn-cgi/l/email-protection#2f495d464a414b5c6f434648475b5f5d405b404c4043014c4042) --- # Creating Airdrops with Compressed Tokens | ZK Compression [PreviousAddresses and URLs](https://www.zkcompression.com/developers/addresses-and-urls) [NextUsing Token-2022](https://www.zkcompression.com/developers/using-token-2022) Last updated 1 month ago Was this helpful? **ZK Compression is the most efficient way to distribute your SPL tokens.** **By the end of this guide, you'll have built a fully functioning, programmatic airdrop.** _Key benefits of compressed tokens:_ * Up to 5000x cheaper than regular tokens * Supported by leading Solana wallets, including Phantom and Backpack * Compatible with existing programs via atomic compression and decompression between SPL <> Compressed tokens [](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#airdropping-spl-tokens) Airdropping SPL Tokens ---------------------------------------------------------------------------------------------------------------------------------------- No-code Solution[](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#no-code-solution) by Helius Labs is an excellent no-code airdrop tool. Airship uses compressed tokens under the hood. For programmatic airdrops with more control, keep reading. The high-level overview is this: 1. Mint and send the to-be-airdropped SPL tokens to a wallet you control. 2. Create batches of instructions based on a list of recipients and amounts. 3. Build transactions from these instruction batches, then sign, send, and confirm them. The code snippets work! You can copy + paste them into your IDE. ### [](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#id-1.-install-the-sdk) 1\. Install the SDK npm [](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#tab-npm) yarn [](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#tab-yarn) pnpm [](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#tab-pnpm) Copy npm install --save \ @lightprotocol/stateless.js \ @lightprotocol/compressed-token \ @solana/web3.js \ @solana/spl-token \ bs58 \ dotenv Copy yarn add \ @lightprotocol/stateless.js \ @lightprotocol/compressed-token \ @solana/web3.js \ @solana/spl-token \ bs58 \ dotenv Copy pnpm add \ @lightprotocol/stateless.js \ @lightprotocol/compressed-token \ @solana/web3.js \ @solana/spl-token \ bs58 \ dotenv ### [](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#id-2.-mint-spl-tokens-to-yourself) 2\. Mint SPL tokens to yourself Default [](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#tab-default) With \`createMint\` helper [](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#tab-with-createmint-helper) Copy import { Keypair } from '@solana/web3.js'; import { createRpc } from '@lightprotocol/stateless.js'; import { createMint, getOrCreateAssociatedTokenAccount, mintTo, } from "@solana/spl-token"; import { createTokenPool } from '@lightprotocol/compressed-token'; import bs58 from "bs58"; import dotenv from "dotenv"; dotenv.config(); // Set these values in your .env file const RPC_ENDPOINT = process.env.RPC_ENDPOINT!; const PAYER = Keypair.fromSecretKey( bs58.decode(process.env.PAYER_KEYPAIR!) ); // Create Rpc endpoint const connection = createRpc(RPC_ENDPOINT); (async() => { /// Create an SPL mint const mint = await createMint( connection, PAYER, PAYER.publicKey, null, 9 ); console.log(`create-mint success! address: ${mint}`); /// Register mint for compression const poolTxId = await createTokenPool(connection, PAYER, mint); console.log(`createTokenPool success: ${poolTxId}`); /// Create an associated SPL token account for the sender (PAYER) const ata = await getOrCreateAssociatedTokenAccount( connection, PAYER, mint, PAYER.publicKey ); console.log(`ATA: ${ata.address.toBase58()}`); /// Mint SPL tokens to the sender const mintToTxId = await mintTo( connection, PAYER, mint, ata.address, PAYER.publicKey, 1e9 * 1e9 // 1b * decimals ); console.log(`mint-to success! txId: ${mintToTxId}`); })(); If you create a new mint, you can use the `createMint` helper from `@lightprotocol/compressed-token`. It creates the mint **and** registers it for compression. Copy import { Keypair } from '@solana/web3.js'; import { createRpc } from '@lightprotocol/stateless.js'; import { createMint } from '@lightprotocol/compressed-token'; import { getOrCreateAssociatedTokenAccount, mintTo, } from "@solana/spl-token"; import bs58 from "bs58"; import dotenv from "dotenv"; dotenv.config(); // Set these values in your .env file const RPC_ENDPOINT = process.env.RPC_ENDPOINT!; const PAYER = Keypair.fromSecretKey( bs58.decode(process.env.PAYER_KEYPAIR!) ); // Create Rpc endpoint const connection = createRpc(RPC_ENDPOINT); (async() => { /// Create an SPL mint + register it for compression. const { mint, transactionSignature } = await createMint( connection, PAYER, PAYER.publicKey, 9, ); console.log(`create-mint success! txId: ${transactionSignature}`); /// Create an associated SPL token account for the sender (PAYER) const ata = await getOrCreateAssociatedTokenAccount( connection, PAYER, mint, PAYER.publicKey ); console.log(`ATA: ${ata.address.toBase58()}`); /// Mint SPL tokens to the sender const mintToTxId = await mintTo( connection, PAYER, mint, ata.address, PAYER.publicKey, 1e9 * 1e9 // 1b * decimals ); console.log(`mint-to success! txId: ${mintToTxId}`); })(); You now have a regular SPL token account owned by `PAYER` that holds all minted tokens. ### [](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#id-3.-distribute-the-tokens) 3\. Distribute the tokens Next, you want to distribute the SPL tokens from your distributor to all recipients. Ensure you have the latest `@lightprotocol/stateless.js` and `@lightprotocol/compressed-token` versions `≥ 0.21.0`! #### [](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#a.-simple-version) A. Simple version **Simple airdrop script**[](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#simple-airdrop-script) Copy import { Keypair, PublicKey, ComputeBudgetProgram } from "@solana/web3.js"; import { CompressedTokenProgram, getTokenPoolInfos, selectTokenPoolInfo, } from "@lightprotocol/compressed-token"; import { bn, buildAndSignTx, calculateComputeUnitPrice, createRpc, dedupeSigner, Rpc, selectStateTreeInfo, sendAndConfirmTx, } from "@lightprotocol/stateless.js"; import { getOrCreateAssociatedTokenAccount } from "@solana/spl-token"; import dotenv from "dotenv"; import bs58 from "bs58"; dotenv.config(); // Set these values in your .env file const RPC_ENDPOINT = process.env.RPC_ENDPOINT; const MINT_ADDRESS = new PublicKey(process.env.MINT_ADDRESS!); const PAYER_KEYPAIR = Keypair.fromSecretKey( bs58.decode(process.env.PAYER_KEYPAIR!) ); (async () => { const connection: Rpc = createRpc(RPC_ENDPOINT); const mintAddress = MINT_ADDRESS; const payer = PAYER_KEYPAIR; const owner = payer; /// Select a new tree for each transaction. const activeStateTrees = await connection.getStateTreeInfos(); const treeInfo = selectStateTreeInfo(activeStateTrees); /// Select a tokenpool info const infos = await getTokenPoolInfos(connection, mintAddress); const info = selectTokenPoolInfo(infos); const sourceTokenAccount = await getOrCreateAssociatedTokenAccount( connection, payer, mintAddress, payer.publicKey ); // Airdrop to example recipient // 1 recipient = 120_000 CU // 5 recipients = 170_000 CU const airDropAddresses = ["GMPWaPPrCeZPse5kwSR3WUrqYAPrVZBSVwymqh7auNW7"].map( (address) => new PublicKey(address) ); const amount = bn(111); const instructions = []; instructions.push( ComputeBudgetProgram.setComputeUnitLimit({ units: 120_000 }), ComputeBudgetProgram.setComputeUnitPrice({ // Replace this with a dynamic priority_fee based on network conditions. microLamports: calculateComputeUnitPrice(20_000, 120_000), }) ); const compressInstruction = await CompressedTokenProgram.compress({ payer: payer.publicKey, owner: owner.publicKey, source: sourceTokenAccount.address, toAddress: airDropAddresses, amount: airDropAddresses.map(() => amount), mint: mintAddress, tokenPoolInfo: info, outputStateTreeInfo: treeInfo, }); instructions.push(compressInstruction); const additionalSigners = dedupeSigner(payer, [owner]); const { blockhash } = await connection.getLatestBlockhash(); const tx = buildAndSignTx(instructions, payer, blockhash, additionalSigners); const txId = await sendAndConfirmTx(connection, tx); console.log(`txId: ${txId}`); })(); #### [](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#b.-optimized-for-large-scale-airdrops) B. Optimized For large-scale airdrops First, create a helper that takes recipients and amounts and returns batches of instructions: 1\. create-instructions.ts[](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#id-1.-create-instructions.ts) Copy // create-instructions.ts import { CompressedTokenProgram, TokenPoolInfo, } from "@lightprotocol/compressed-token"; import { bn, selectStateTreeInfo, StateTreeInfo, } from "@lightprotocol/stateless.js"; import { ComputeBudgetProgram, TransactionInstruction, PublicKey, } from "@solana/web3.js"; interface CreateAirdropInstructionsParams { amount: number | bigint; recipients: PublicKey[]; payer: PublicKey; sourceTokenAccount: PublicKey; mint: PublicKey; stateTreeInfos: StateTreeInfo[]; tokenPoolInfos: TokenPoolInfo[]; maxRecipientsPerInstruction?: number; maxInstructionsPerTransaction?: number; computeUnitLimit?: number; computeUnitPrice?: number | undefined; } export type InstructionBatch = TransactionInstruction[]; export async function createAirdropInstructions({ amount, recipients, payer, sourceTokenAccount, mint, stateTreeInfos, tokenPoolInfos, maxRecipientsPerInstruction = 5, maxInstructionsPerTransaction = 3, computeUnitLimit = 500_000, computeUnitPrice = undefined, }: CreateAirdropInstructionsParams): Promise { const instructionBatches: InstructionBatch[] = []; const amountBn = bn(amount.toString()); // Process recipients in chunks for ( let i = 0; i < recipients.length; i += maxRecipientsPerInstruction * maxInstructionsPerTransaction ) { const instructions: TransactionInstruction[] = []; instructions.push( ComputeBudgetProgram.setComputeUnitLimit({ units: computeUnitLimit }) ); if (computeUnitPrice) { instructions.push( ComputeBudgetProgram.setComputeUnitPrice({ microLamports: computeUnitPrice, }) ); } const treeInfo = selectStateTreeInfo(stateTreeInfos); const tokenPoolInfo = selectTokenPoolInfo(tokenPoolInfos); for (let j = 0; j < maxInstructionsPerTransaction; j++) { const startIdx = i + j * maxRecipientsPerInstruction; const recipientBatch = recipients.slice( startIdx, startIdx + maxRecipientsPerInstruction ); if (recipientBatch.length === 0) break; const compressIx = await CompressedTokenProgram.compress({ payer, owner: payer, source: sourceTokenAccount, toAddress: recipientBatch, amount: recipientBatch.map(() => amountBn), mint, tokenPoolInfo, outputStateTreeInfo: treeInfo, }); instructions.push(compressIx); } if ( (computeUnitPrice && instructions.length > 2) || (!computeUnitPrice && instructions.length > 1) ) { instructionBatches.push(instructions); } } return instructionBatches; } Now, you can create the logic that signs and sends transactions in batches. For this, first add a helper method that refreshes Solana blockhashes in the background: 2\. update-blockhash.ts[](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#id-2.-update-blockhash.ts) Copy // update-blockhash.ts import { Rpc } from "@lightprotocol/stateless.js"; export let currentBlockhash: string; export async function updateBlockhash( connection: Rpc, signal: AbortSignal ): Promise { try { const { blockhash } = await connection.getLatestBlockhash(); currentBlockhash = blockhash; console.log(`Initial blockhash: ${currentBlockhash}`); } catch (error) { console.error("Failed to fetch initial blockhash:", error); return; } // Update blockhash in the background (function updateInBackground() { if (signal.aborted) return; const timeoutId = setTimeout(async () => { if (signal.aborted) return; try { const { blockhash } = await connection.getLatestBlockhash(); currentBlockhash = blockhash; console.log(`Updated blockhash: ${currentBlockhash}`); } catch (error) { console.error("Failed to update blockhash:", error); } updateInBackground(); }, 30_000); signal.addEventListener("abort", () => clearTimeout(timeoutId)); })(); } Then, add the helper that signs and sends the transactions using recent blockhashes. 3\. sign-and-send.ts[](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#id-3.-sign-and-send.ts) Copy // sign-and-send.ts import { Rpc, sendAndConfirmTx } from "@lightprotocol/stateless.js"; import { Keypair, PublicKey, TransactionMessage, VersionedTransaction, } from "@solana/web3.js"; import { InstructionBatch } from "./create-instructions"; import { currentBlockhash, updateBlockhash } from "./update-blockhash"; import bs58 from "bs58"; export enum BatchResultType { Success = "success", Error = "error", } export type BatchResult = | { type: BatchResultType.Success; index: number; signature: string } | { type: BatchResultType.Error; index: number; error: string }; export async function* signAndSendAirdropBatches( batches: InstructionBatch[], payer: Keypair, connection: Rpc, maxRetries = 3 ): AsyncGenerator { const abortController = new AbortController(); const { signal } = abortController; await updateBlockhash(connection, signal); const statusMap = new Array(batches.length).fill(0); // Initialize all as pending (0) // Use zk-compression LUT for your network // https://www.zkcompression.com/developers/protocol-addresses-and-urls#lookup-tables const lookupTableAddress = new PublicKey( "9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ" ); // Get the lookup table account const lookupTableAccount = ( await connection.getAddressLookupTable(lookupTableAddress) ).value!; while (statusMap.includes(0)) { // Continue until all are confirmed or errored const pendingBatches = statusMap.filter((status) => status === 0).length; console.log(`Sending ${pendingBatches} transactions`); const sends = statusMap.map(async (status, index) => { if (status !== 0) return; // Skip non-pending batches let retries = 0; while (retries < maxRetries && statusMap[index] === 0) { if (!currentBlockhash) { console.warn("Waiting for blockhash to be set..."); await new Promise((resolve) => setTimeout(resolve, 1000)); continue; } try { const tx = new VersionedTransaction( new TransactionMessage({ payerKey: payer.publicKey, recentBlockhash: currentBlockhash, instructions: batches[index], }).compileToV0Message([lookupTableAccount]) ); tx.sign([payer]); const sig = bs58.encode(tx.signatures[0]); console.log(`Batch ${index} signature: ${sig}`); const confirmedSig = await sendAndConfirmTx(connection, tx, { skipPreflight: true, commitment: "confirmed", }); if (confirmedSig) { statusMap[index] = 1; // Mark as confirmed return { type: BatchResultType.Success, index, signature: confirmedSig, }; } } catch (e) { retries++; console.warn(`Retrying batch ${index}, attempt ${retries + 1}`); if (retries >= maxRetries) { statusMap[index] = `err: ${(e as Error).message}`; // Mark as error return { type: BatchResultType.Error, index, error: (e as Error).message, }; } } } }); const results = await Promise.all(sends); for (const result of results) { if (result) yield result as BatchResult; } } // Stop the blockhash update loop abortController.abort(); } Finally, put it all together in your main file: airdrop.ts (entrypoint file)[](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#airdrop.ts-entrypoint-file) Copy // airdrop.ts import { Keypair, LAMPORTS_PER_SOL, PublicKey } from "@solana/web3.js"; import { calculateComputeUnitPrice, createRpc, Rpc, } from "@lightprotocol/stateless.js"; import { createMint, getTokenPoolInfos } from "@lightprotocol/compressed-token"; import { getOrCreateAssociatedTokenAccount, mintTo } from "@solana/spl-token"; import { createAirdropInstructions } from "./create-instructions"; import { BatchResultType, signAndSendAirdropBatches } from "./sign-and-send"; import dotenv from "dotenv"; import bs58 from "bs58"; dotenv.config(); const RPC_ENDPOINT = `https://mainnet.helius-rpc.com?api-key=${process.env.HELIUS_API_KEY}`; const connection: Rpc = createRpc(RPC_ENDPOINT); const PAYER = Keypair.fromSecretKey(bs58.decode(process.env.PAYER_KEYPAIR!)); // These are 20 example Solana Pubkeys const recipients = [\ "GMPWaPPrCeZPse5kwSR3WUrqYAPrVZBSVwymqh7auNW7",\ "GySGrTgPtPfMtYoYTmwUdUDFwVJbFMfip7QZdhgXp8dy",\ "Bk1r2vcgX2uTzwV3AUyfRbSfGKktoQrQufBSrHzere74",\ "8BvkadZ6ycFNmQF7S1MHRvEVNb1wvDBFdjkAUnxjK9Ug",\ "EmxcvFKXsWLzUho8AhV9LCKeKRFHg5gAs4sKNJwhe5PF",\ "6mqdHkSpcvNexmECjp5XLt9V9KnSQre9TvbMLGr6sEPM",\ "3k4MViTWXBjFvoUZiJcNGPvzrqnTa41gcrbWCMMnV6ys",\ "2k6BfYRUZQHquPtpkyJpUx3DzM7W3K6H95igtJk8ztpd",\ "89jPyNNLCcqWn1RZThSS4jSqU5VCJkR5mAaSaVzuuqH4",\ "3MzSRLf9jSt6d1MFFMMtPfUcDY6XziRxTB8C5mfvgxXG",\ "9A1H6f3N8mpAPSdfqvYRD4cM1NwDZoMe3yF5DwibL2R2",\ "PtUAhLvUsVcoesDacw198SsnMoFNVskR5pT3QvsBSQw",\ "6C6W6WpgFK8TzTTMNCPMz2t9RaMs4XnkfB6jotrWWzYJ",\ "8sLy9Jy8WSh6boq9xgDeBaTznn1wb1uFpyXphG3oNjL5",\ "GTsQu2XCgkUczigdBFTWKrdDgNKLs885jKguyhkqdPgV",\ "85UK4bjC71Jwpyn8mPSaW3oYyEAiHPbESByq9s5wLcke",\ "9aEJT4CYHEUWwwSQwueZc9EUjhWSLD6AAbpVmmKDeP7H",\ "CY8QjRio1zd9bYWMKiVRrDbwVenf3JzsGf5km5zLgY9n",\ "CeHbdxgYifYhpB6sXGonKzmaejqEfq2ym5utTmB6XMVv",\ "4z1qss12DjUzGUkK1fFesqrUwrEVJJvzPMNkwqYnbAR5",\ ].map((address) => new PublicKey(address)); (async () => { /// Create an SPL mint + register it for compression. const { mint, transactionSignature } = await createMint( connection, PAYER, PAYER.publicKey, 9 ); console.log( `create-mint success! txId: ${transactionSignature}, mint: ${mint.toBase58()}` ); /// Create an associated SPL token account for the sender (PAYER) const ata = await getOrCreateAssociatedTokenAccount( connection, PAYER, mint, PAYER.publicKey ); console.log(`ATA: ${ata.address.toBase58()}`); /// Mint SPL tokens to the sender const mintToTxId = await mintTo( connection, PAYER, mint, ata.address, PAYER.publicKey, 10e9 * LAMPORTS_PER_SOL // 10B tokens * decimals ); console.log(`mint-to success! txId: ${mintToTxId}`); const stateTreeInfos = await connection.getStateTreeInfos(); const tokenPoolInfos = await getTokenPoolInfos(connection, mint); const instructionBatches = await createAirdropInstructions({ amount: 1e6, recipients, payer: PAYER.publicKey, sourceTokenAccount: ata.address, mint, stateTreeInfos, tokenPoolInfos, computeUnitPrice: calculateComputeUnitPrice(10_000, 500_000), }); for await (const result of signAndSendAirdropBatches( instructionBatches, PAYER, connection )) { if (result.type === BatchResultType.Success) { console.log(`Batch ${result.index} confirmed: ${result.signature}`); } else if (result.type === BatchResultType.Error) { console.log(`Batch ${result.index} failed: ${result.error}`); // Use result.index to access the specific batch in instructionBatches const failedBatch = instructionBatches[result.index]; console.log(`Failed batch instructions:`, failedBatch); // Additional logic to handle failed instructions } } console.log("Airdrop process complete."); })(); Ensure that you have all the necessary `.env` variables set up. You can now run your code and execute the airdrop! [](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#advanced-decompress-claim) Advanced: Decompress / Claim ------------------------------------------------------------------------------------------------------------------------------------------------- **Decompress SPL Tokens**[](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#decompress-spl-tokens) Copy import { bn, buildAndSignTx, sendAndConfirmTx, dedupeSigner, Rpc, createRpc, } from "@lightprotocol/stateless.js"; import { ComputeBudgetProgram, Keypair, PublicKey } from "@solana/web3.js"; import { CompressedTokenProgram, getTokenPoolInfos, selectMinCompressedTokenAccountsForTransfer, selectTokenPoolInfosForDecompression, } from "@lightprotocol/compressed-token"; import { getOrCreateAssociatedTokenAccount } from "@solana/spl-token"; import bs58 from "bs58"; import dotenv from "dotenv"; dotenv.config(); // Set these values in your .env file const RPC_ENDPOINT = process.env.RPC_ENDPOINT; const mint = new PublicKey(process.env.MINT_ADDRESS!); const payer = Keypair.fromSecretKey(bs58.decode(process.env.PAYER_KEYPAIR!)); const owner = payer; const amount = 1e5; const connection: Rpc = createRpc(RPC_ENDPOINT); (async () => { // 1. Create an associated token account for the user if it doesn't exist const ata = await getOrCreateAssociatedTokenAccount( connection, payer, mint, payer.publicKey ); // 2. Fetch compressed token accounts const compressedTokenAccounts = await connection.getCompressedTokenAccountsByOwner(owner.publicKey, { mint, }); // 3. Select const [inputAccounts] = selectMinCompressedTokenAccountsForTransfer( compressedTokenAccounts.items, bn(amount) ); // 4. Fetch validity proof const proof = await connection.getValidityProof( inputAccounts.map((account) => account.compressedAccount.hash) ); // 5. Fetch token pool infos const tokenPoolInfos = await getTokenPoolInfos(connection, mint); // 6. Select const selectedTokenPoolInfos = selectTokenPoolInfosForDecompression( tokenPoolInfos, amount ); // 7. Build instruction const ix = await CompressedTokenProgram.decompress({ payer: payer.publicKey, inputCompressedTokenAccounts: inputAccounts, toAddress: ata.address, amount, tokenPoolInfos: selectedTokenPoolInfos, recentInputStateRootIndices: proof.rootIndices, recentValidityProof: proof.compressedProof, }); // 8. Sign, send, and confirm const { blockhash } = await connection.getLatestBlockhash(); const additionalSigners = dedupeSigner(payer, [owner]); const signedTx = buildAndSignTx( [ComputeBudgetProgram.setComputeUnitLimit({ units: 300_000 }), ix], payer, blockhash, additionalSigners ); return await sendAndConfirmTx(connection, signedTx); })(); [](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#advanced-tips) Advanced Tips ---------------------------------------------------------------------------------------------------------------------- [](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#native-swap-via-jup-api) Native Swap via Jup-API ------------------------------------------------------------------------------------------------------------------------------------------ * * * [](https://www.zkcompression.com/developers/creating-airdrops-with-compressed-tokens#support) Support ---------------------------------------------------------------------------------------------------------- Compressed tokens are supported in major Solana wallets like Phantom and Backpack. Still, you can let users decompress to SPL via your Frontend (FE) to customize claims. Here's how Set priority fees dynamically for decompression. Learn more . If you have a custom FE, you can let users swap compressed tokens using the Jup-API. A reference implementation is available . For additional support or questions, please refer to our , or contact or on Telegram or via . 👇 👇 [Airship](https://airship.helius.dev/) [here](https://docs.helius.dev/guides/sending-transactions-on-solana#summary) [here](https://github.com/Lightprotocol/example-jupiter-swap-node) [documentation](https://www.zkcompression.com/) [Swen](https://t.me/swen_light) [Mert](https://t.me/mert_helius) [email](https://www.zkcompression.com/cdn-cgi/l/email-protection#0e687c676b606a7d4e626769667a7e7c617a616d6162206d6163) --- # Email Protection | Cloudflare Please enable cookies. Email Protection ================ You are unable to access this email address zkcompression.com ------------------------------------------------------------- The website from which you got to this page is protected by Cloudflare. Email addresses on that page have been hidden in order to keep them from being accessed by malicious bots. **You must enable Javascript in your browser in order to decode the e-mail address**. If you have a website and are interested in protecting it in a similar way, you can [sign up for Cloudflare](https://www.cloudflare.com/sign-up?utm_source=email_protection) . * [How does Cloudflare protect email addresses on website from spammers?](https://developers.cloudflare.com/waf/tools/scrape-shield/email-address-obfuscation/) * [Can I sign up for Cloudflare?](https://developers.cloudflare.com/fundamentals/setup/account/create-account/) Cloudflare Ray ID: **94d9b5cffd451752** • Your IP: Click to reveal 54.237.218.47 • Performance & security by [Cloudflare](https://www.cloudflare.com/5xx-error-landing) ---