diff --git a/.gitignore b/.gitignore
index bc29d0c..bd44d77 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,5 @@ mintlify-docs/
# Dependencies
node_modules/
+
+stash
\ No newline at end of file
diff --git a/compressed-pdas/create-a-program-with-compressed-pdas.mdx b/compressed-pdas/overview.mdx
similarity index 100%
rename from compressed-pdas/create-a-program-with-compressed-pdas.mdx
rename to compressed-pdas/overview.mdx
diff --git a/cspell.json b/cspell.json
index 0a506eb..4ea32a3 100644
--- a/cspell.json
+++ b/cspell.json
@@ -175,7 +175,16 @@
"stablecoins",
"fintechs",
"micropayments",
- "clawback"
+ "clawback",
+ "hackathon",
+ "altbn",
+ "circom",
+ "snarkjs",
+ "Zcash",
+ "zcash",
+ "circomlibjs",
+ "Jotaro",
+ "Yano"
],
"ignorePaths": [
"node_modules",
diff --git a/docs.json b/docs.json
index 7b29115..050a5c2 100644
--- a/docs.json
+++ b/docs.json
@@ -99,6 +99,33 @@
"quickstart"
]
},
+ {
+ "group": "ZK",
+ "pages": [
+ "zk/overview",
+ "zk/examples"
+ ]
+ },
+ {
+ "group": "Compressed PDAs",
+ "pages": [
+ "compressed-pdas/overview",
+ {
+ "group": "Program Guides",
+ "pages": [
+ "compressed-pdas/guides",
+ "compressed-pdas/guides/how-to-create-compressed-accounts",
+ "compressed-pdas/guides/how-to-update-compressed-accounts",
+ "compressed-pdas/guides/how-to-close-compressed-accounts",
+ "compressed-pdas/guides/how-to-reinitialize-compressed-accounts",
+ "compressed-pdas/guides/how-to-burn-compressed-accounts"
+ ]
+ },
+ "compressed-pdas/program-examples",
+ "client-library/client-guide",
+ "compressed-pdas/solana-attestation-service"
+ ]
+ },
{
"group": "Compressed Tokens",
"pages": [
@@ -144,26 +171,6 @@
}
]
},
- {
- "group": "Compressed PDAs",
- "pages": [
- "compressed-pdas/create-a-program-with-compressed-pdas",
- {
- "group": "Program Guides",
- "pages": [
- "compressed-pdas/guides",
- "compressed-pdas/guides/how-to-create-compressed-accounts",
- "compressed-pdas/guides/how-to-update-compressed-accounts",
- "compressed-pdas/guides/how-to-close-compressed-accounts",
- "compressed-pdas/guides/how-to-reinitialize-compressed-accounts",
- "compressed-pdas/guides/how-to-burn-compressed-accounts"
- ]
- },
- "compressed-pdas/program-examples",
- "client-library/client-guide",
- "compressed-pdas/solana-attestation-service"
- ]
- },
{
"group": "JSON RPC Methods",
"pages": [
diff --git a/home.mdx b/home.mdx
index 5beda94..061f242 100644
--- a/home.mdx
+++ b/home.mdx
@@ -189,7 +189,7 @@ import WelcomePageInstall from "/snippets/setup/welcome-page-install.mdx";
Program and client guides for rent-free PDA accounts.
diff --git a/learn/core-concepts/considerations.mdx b/learn/core-concepts/considerations.mdx
index 94eaaf3..0651fff 100644
--- a/learn/core-concepts/considerations.mdx
+++ b/learn/core-concepts/considerations.mdx
@@ -81,7 +81,7 @@ You're ready to take the next step and start building!
title="Compressed PDAs"
icon="chevron-right"
color="#0066ff"
- href="/compressed-pdas/create-a-program-with-compressed-pdas"
+ href="/compressed-pdas/overview"
horizontal
/>
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 7b54323..0ca6b8f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,7 +8,7 @@
"name": "docs-v2",
"version": "1.0.0",
"devDependencies": {
- "cspell": "^8.6.0",
+ "cspell": "^8.19.4",
"eslint": "^8.57.0",
"eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^4.6.2",
diff --git a/package.json b/package.json
index 938ade2..2cecceb 100644
--- a/package.json
+++ b/package.json
@@ -12,11 +12,10 @@
"ci": "npm run format:check && npm run lint && npm run spellcheck"
},
"devDependencies": {
- "cspell": "^8.6.0",
+ "cspell": "^8.19.4",
"eslint": "^8.57.0",
"eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^4.6.2",
"prettier": "^3.2.5"
}
}
-
diff --git a/references/migration-v1-to-v2.mdx b/references/migration-v1-to-v2.mdx
index 515dfda..907cb7c 100644
--- a/references/migration-v1-to-v2.mdx
+++ b/references/migration-v1-to-v2.mdx
@@ -4,15 +4,16 @@ description: V2 reduces CU consumption by up to 70%. V1 remains supported for ex
sidebarTitle: V2 Migration Guide
---
-## V2 Improvements
+import V1ToV2MigrationPrompt from "/snippets/ai-prompts/v1-to-v2-migration.mdx";
-| | v1 | v2 |
-|---------------------|------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------|
-| Merkle tree type | Concurrent | Batched |
-| State tree depth | 26 (~67M leaves) | 32 (~4B leaves) |
-| Address tree depth | 26 | 40 |
-| Address tree accounts| Separate tree + queue | Single batch tree |
+## V2 Improvements
+| | v1 | v2 |
+|-----------------------|-----------------------|--------------------|
+| Merkle tree type | Concurrent | Batched |
+| State tree depth | 26 (~67M leaves) | 32 (~4B leaves) |
+| Address tree depth | 26 | 40 |
+| Address tree accounts | Separate tree + queue | Single batch tree |
@@ -250,6 +251,11 @@ let new_address_params = instruction_data
.into_new_address_params_assigned_packed(address_seed, Some(0));
```
+
+
+
+
+
diff --git a/resources/addresses-and-urls.mdx b/resources/addresses-and-urls.mdx
index 0c66e2f..c04589f 100644
--- a/resources/addresses-and-urls.mdx
+++ b/resources/addresses-and-urls.mdx
@@ -87,7 +87,6 @@ Find all JSON RPC Methods for ZK Compression [here](/api-reference/json-rpc-meth
-
## Address Trees & Queues
diff --git a/resources/cli-installation.mdx b/resources/cli-installation.mdx
index ed7a6ce..d80cda7 100644
--- a/resources/cli-installation.mdx
+++ b/resources/cli-installation.mdx
@@ -253,7 +253,7 @@ FLAGS
title="Build with compressed PDAs"
icon="chevron-right"
color="#0066ff"
- href="/compressed-pdas/create-a-program-with-compressed-pdas"
+ href="/compressed-pdas/overview"
horizontal
/>
diff --git a/snippets/ai-prompts/v1-to-v2-migration.mdx b/snippets/ai-prompts/v1-to-v2-migration.mdx
new file mode 100644
index 0000000..f6743d3
--- /dev/null
+++ b/snippets/ai-prompts/v1-to-v2-migration.mdx
@@ -0,0 +1,105 @@
+---
+argument-hint:
+description: Migrate Light Protocol program from v1 to v2 Merkle trees
+allowed-tools: [Bash, Read, Glob, Grep, Task, WebFetch]
+---
+
+Migrate this Light Protocol program from v1 to v2 Merkle trees.
+
+## Goal
+
+Produce a **fully working migration** that builds and tests pass.
+
+## Available commands
+
+Via Bash tool:
+- `cargo build-sbf`, `cargo test-sbf`, `cargo fmt`, `cargo clippy`
+- `anchor build`, `anchor test`
+- `grep`, `sed`
+
+## Documentation
+
+- Migration Guide: https://zkcompression.com/references/migration-v1-to-v2
+- Reference PR: https://github.com/Lightprotocol/program-examples/commit/54f0e7f15c2972a078f776cfb40b238d83c7e486
+
+## Reference repos
+
+program-examples/counter/anchor/
+├── programs/counter/src/lib.rs # v2 patterns: derive_address, CpiAccounts
+├── Cargo.toml # v2 feature flags
+└── tests/counter.ts # v2 client patterns
+
+## Workflow
+
+### Phase 1: Index program
+
+Find all v1 patterns:
+
+ grep -r "::v1::" src/ tests/
+ grep -r "ADDRESS_TREE_V1" src/
+ grep -r "into_new_address_params_packed" src/
+ grep -r "get_address_tree_v1" tests/
+
+### Phase 2: Update dependencies
+
+Add v2 feature to Cargo.toml:
+
+ [dependencies]
+ light-sdk = { version = "0.17", features = ["anchor", "v2"] }
+ light-sdk-types = { version = "0.17", features = ["v2"] }
+
+ [dev-dependencies]
+ light-program-test = { version = "0.17", features = ["v2"] }
+ light-client = { version = "0.17", features = ["v2"] }
+
+### Phase 3: Rust SDK replacements
+
+| v1 Pattern | v2 Replacement |
+|------------|----------------|
+| address::v1::derive_address | address::v2::derive_address |
+| cpi::v1::CpiAccounts | cpi::v2::CpiAccounts |
+| cpi::v1::LightSystemProgramCpi | cpi::v2::LightSystemProgramCpi |
+| constants::ADDRESS_TREE_V1 | light_sdk_types::ADDRESS_TREE_V2 |
+| .into_new_address_params_packed(seed) | .into_new_address_params_assigned_packed(seed, Some(0)) |
+| .add_system_accounts(config) | .add_system_accounts_v2(config) |
+
+### Phase 4: TypeScript SDK replacements
+
+| v1 Pattern | v2 Replacement |
+|------------|----------------|
+| deriveAddress( | deriveAddressV2( |
+| deriveAddressSeed( | deriveAddressSeedV2( |
+| defaultTestStateTreeAccounts().addressTree | batchAddressTree |
+| .newWithSystemAccounts( | .newWithSystemAccountsV2( |
+| get_address_tree_v1() | get_address_tree_v2() |
+| get_random_state_tree_info_v1() | get_random_state_tree_info() |
+
+### Phase 5: Build and test loop
+
+**Required commands (no shortcuts):**
+
+For Anchor programs: `anchor build && anchor test`
+
+For Native programs: `cargo build-sbf && cargo test-sbf`
+
+**NO shortcuts allowed:**
+
+- Do NOT use `cargo build` (must use `cargo build-sbf`)
+- Do NOT use `cargo test` (must use `cargo test-sbf`)
+- Tests MUST run against real BPF bytecode
+
+**On failure:** Spawn debugger agent with error context.
+
+**Loop rules:**
+
+1. Each debugger gets fresh context + previous debug reports
+2. Each attempt tries something DIFFERENT
+3. **NEVER GIVE UP** - keep spawning until fixed
+
+Do NOT proceed until all tests pass.
+
+## DeepWiki fallback
+
+If no matching pattern in reference repos:
+
+ mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "How to migrate {pattern} from v1 to v2?")
\ No newline at end of file
diff --git a/snippets/mermaid/nullifier-flow.mdx b/snippets/mermaid/nullifier-flow.mdx
new file mode 100644
index 0000000..fdf228b
--- /dev/null
+++ b/snippets/mermaid/nullifier-flow.mdx
@@ -0,0 +1,18 @@
+```mermaid
+sequenceDiagram
+ participant U as User
+ participant C as Client
+ participant P as Program
+ participant L as Light Protocol
+
+ U->>C: secret + verification_id
+ C->>C: nullifier = Poseidon(vid, secret)
+ C->>C: proof = Groth16.prove(...)
+ C->>P: create_nullifier(proof, vid, nullifier)
+ P->>P: Groth16.verify(proof)
+ P->>L: derive_address(nullifier, vid)
+ L-->>P: address
+ P->>L: create_account(address)
+ L-->>P: success/fail
+ P-->>U: tx result
+```
diff --git a/snippets/overview-tables/zk-examples-table.mdx b/snippets/overview-tables/zk-examples-table.mdx
new file mode 100644
index 0000000..faf4bb3
--- /dev/null
+++ b/snippets/overview-tables/zk-examples-table.mdx
@@ -0,0 +1,4 @@
+| | Description |
+|:--------|:------------|
+| [ZK-ID](https://github.com/Lightprotocol/program-examples/tree/main/zk/zk-id) | Identity verification using Groth16 proofs. Issuers create credentials; users prove ownership without revealing the credential. |
+| [Nullifier](https://github.com/Lightprotocol/program-examples/tree/main/zk/zk-nullifier) | Simple Program to Create Nullifiers. |
diff --git a/welcome.mdx b/welcome.mdx
index 9f0a4d6..16f17ef 100644
--- a/welcome.mdx
+++ b/welcome.mdx
@@ -24,7 +24,7 @@ import WelcomePageInstall from "/snippets/setup/welcome-page-install.mdx";
For App State.
diff --git a/zk/examples.mdx b/zk/examples.mdx
new file mode 100644
index 0000000..cb45dc4
--- /dev/null
+++ b/zk/examples.mdx
@@ -0,0 +1,10 @@
+---
+title: Examples
+description: Example projects for building privacy applications on Solana.
+keywords: ["privacy examples solana", "zk examples solana", "private payments examples", "zk identity solana"]
+---
+
+import ZkExamplesTable from "/snippets/overview-tables/zk-examples-table.mdx";
+
+
+
diff --git a/zk/overview.mdx b/zk/overview.mdx
new file mode 100644
index 0000000..969e82b
--- /dev/null
+++ b/zk/overview.mdx
@@ -0,0 +1,128 @@
+---
+title: Primitives for ZK on Solana
+sidebarTitle: Overview
+description: Overview how to build a ZK program on Solana.
+keywords: ["nullifiers on Solana", "zcash on solana", "privacy on solana", "zk on solana", "solana privacy hackathon", "private payments solana", "privacy tooling solana"]
+---
+
+import ZkExamplesTable from "/snippets/overview-tables/zk-examples-table.mdx";
+
+---
+
+Building a ZK Solana program requires:
+1. Nullifiers to prevent double spending
+2. Proof verification
+3. A Merkle tree to store state
+4. An indexer to serve Merkle proofs
+5. Encrypted state
+
+## Nullifiers on Solana
+
+A nullifier is a deterministically derived hash to ensure an action can only be performed once.
+The nullifier cannot be linked to the action or user.
+For example Zcash uses nullifiers to prevent double spending.
+
+To implement nullifiers we need a data structure that ensures every nullifier is only created once and never deleted.
+On Solana a straight forward way to implement nullifiers is to create a PDA account with the nullifier as seed.
+* PDA accounts cannot be closed and permanently lock 890,880 lamports (per nullifier rent-exemption).
+* Compressed PDAs are derived similar to Solana PDAs and cost 15,000 lamports to create (no rent-exemption).
+
+| Storage | Cost per nullifier |
+|---------|-------------------|
+| PDA | 890,880 lamports |
+| Compressed PDA | 15,000 lamports |
+
+
+[See full example with tests on on Github](https://github.com/Lightprotocol/program-examples/tree/main/zk/nullifier).
+
+
+```rust
+// add to your program
+use anchor_lang::prelude::*;
+use nullifier_creation::{create_nullifiers, NullifierInstructionData};
+
+declare_id!("Bw8aty8LJY5Kg2b6djghjWGwt6cBc1tVQUoreUehvVq4");
+
+#[program]
+pub mod zk_nullifier {
+ use super::*;
+
+ pub fn create_nullifier<'info>(
+ ctx: Context<'_, '_, '_, 'info, CreateNullifierAccounts<'info>>,
+ data: NullifierInstructionData,
+ nullifiers: Vec<[u8; 32]>,
+ ) -> Result<()> {
+ // Verify your proof here. Use nullifiers as public inputs
+ // among your other public inputs.
+ // Example:
+ // let public_inputs = [...nullifiers, ...your_other_inputs];
+ // Groth16Verifier::new(...).verify()?;
+
+ create_nullifiers(
+ &nullifiers,
+ data,
+ ctx.accounts.signer.as_ref(),
+ ctx.remaining_accounts,
+ )
+ }
+}
+
+#[derive(Accounts)]
+pub struct CreateNullifierAccounts<'info> {
+ #[account(mut)]
+ pub signer: Signer<'info>,
+}
+```
+
+## Groth16 Proof Verification on Solana
+
+Groth16's small proof size and fast verification (~200k compute units) make it the practical choice for Solana.
+
+
+Find more information on [docs.rs](https://docs.rs/groth16-solana) and [Github](https://github.com/Lightprotocol/groth16-solana).
+
+
+```rust
+let mut public_inputs_vec = Vec::new();
+for input in PUBLIC_INPUTS.chunks(32) {
+ public_inputs_vec.push(input);
+}
+
+let proof_a: G1 =
+ ::read(&*[&change_endianness(&PROOF[0..64])[..], &[0u8][..]].concat())
+ .unwrap();
+let mut proof_a_neg = [0u8; 65];
+::write(&proof_a.neg(), &mut proof_a_neg[..]).unwrap();
+
+let proof_a = change_endianness(&proof_a_neg[..64]).try_into().unwrap();
+let proof_b = PROOF[64..192].try_into().unwrap();
+let proof_c = PROOF[192..256].try_into().unwrap();
+
+let mut verifier = Groth16Verifier::new(
+ &proof_a,
+ &proof_b,
+ &proof_c,
+ public_inputs_vec.as_slice(),
+ &VERIFYING_KEY,
+)
+.unwrap();
+verifier.verify().unwrap();
+```
+
+## Merklelized State with Indexer Support
+
+ZK applications on Solana can use existing state Merkle trees to store state in rent-free accounts.
+* This way you don't need to maintain your own Merkle tree and indexer.
+* RPCs that support ZK Compression (Helius, Triton) index state changes.
+
+| Creation | Regular PDA Account | Compressed PDA |
+| :------------- | :--------------------- | :---------------------- |
+| 100-byte PDA | ~1,600,000 lamports | 15,000 lamports |
+
+
+Your circuit must include compressed accounts. Find [guides to compressed accounts in the documentation](/compressed-pdas/overview) and the [full example with zk implementation here](https://github.com/Lightprotocol/program-examples/blob/99d260f9f356743b8fe3501c684f7926930d6079/zk-id/circuits/compressed_account.circom).
+
+
+## Get Started & Examples
+
+
\ No newline at end of file