diff --git a/program-libs/account-checks/.cargo-rdme.toml b/program-libs/account-checks/.cargo-rdme.toml new file mode 100644 index 0000000000..ff280e7a26 --- /dev/null +++ b/program-libs/account-checks/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-account-checks" +heading-base-level = 0 diff --git a/program-libs/account-checks/Cargo.toml b/program-libs/account-checks/Cargo.toml index 04007b328e..89290c8671 100644 --- a/program-libs/account-checks/Cargo.toml +++ b/program-libs/account-checks/Cargo.toml @@ -2,6 +2,7 @@ name = "light-account-checks" version = "0.7.0" description = "Checks for solana accounts." +readme = "README.md" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" edition = "2021" diff --git a/program-libs/account-checks/README.md b/program-libs/account-checks/README.md new file mode 100644 index 0000000000..97582f1050 --- /dev/null +++ b/program-libs/account-checks/README.md @@ -0,0 +1,16 @@ + + +# light-account-checks + +Checks for Solana accounts. + +| Module | Description | +|--------|-------------| +| [`AccountInfoTrait`] | Trait abstraction over Solana account info types | +| [`AccountIterator`] | Iterates over a slice of accounts by index | +| [`AccountError`] | Error type for account validation failures | +| [`checks`] | Owner, signer, writable, and rent-exempt checks | +| [`discriminator`] | Account discriminator constants and validation | +| [`packed_accounts`] | Packed account struct deserialization | + + diff --git a/program-libs/account-checks/src/lib.rs b/program-libs/account-checks/src/lib.rs index b2d0db0825..5d973032b3 100644 --- a/program-libs/account-checks/src/lib.rs +++ b/program-libs/account-checks/src/lib.rs @@ -1,3 +1,16 @@ +//! # light-account-checks +//! +//! Checks for Solana accounts. +//! +//! | Module | Description | +//! |--------|-------------| +//! | [`AccountInfoTrait`] | Trait abstraction over Solana account info types | +//! | [`AccountIterator`] | Iterates over a slice of accounts by index | +//! | [`AccountError`] | Error type for account validation failures | +//! | [`checks`] | Owner, signer, writable, and rent-exempt checks | +//! | [`discriminator`] | Account discriminator constants and validation | +//! | [`packed_accounts`] | Packed account struct deserialization | + #![cfg_attr(not(feature = "std"), no_std)] pub mod account_info; diff --git a/program-libs/aligned-sized/.cargo-rdme.toml b/program-libs/aligned-sized/.cargo-rdme.toml new file mode 100644 index 0000000000..25e653f4ab --- /dev/null +++ b/program-libs/aligned-sized/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "aligned-sized" +heading-base-level = 0 diff --git a/program-libs/aligned-sized/README.md b/program-libs/aligned-sized/README.md index 73d256e7ad..6df64250db 100644 --- a/program-libs/aligned-sized/README.md +++ b/program-libs/aligned-sized/README.md @@ -1,2 +1,27 @@ -# aligned-sized -A macro which ensures the alignment and calculates the size of a struct + + +**aligned-sized** is a library providing the `aligned_sized` macro, which: + +* Calculates a size of the given struct and provides a `LEN` constant with + that value. + +Future plans: + +* Ensuring that the struct is aligned, adding padding fields when + necessary. + +# Motivation + +Calculating the size of a struct is often a necessity when developing +project in Rust, in particular: + +* [Solana](https://solana.com/) programs, also when using + [Anchor](https://www.anchor-lang.com/) framework. +* [eBPF](https://ebpf.io/) programs written in [Aya](https://aya-rs.dev/). + +This library provides a macro which automatically calculates the size, +also taking in account factors which make a straightforward use of +`core::mem::size_of::` for the whole struct impossible (discriminants, +vectors etc.). + + diff --git a/program-libs/aligned-sized/src/lib.rs b/program-libs/aligned-sized/src/lib.rs index 7bb4964610..339007bd11 100644 --- a/program-libs/aligned-sized/src/lib.rs +++ b/program-libs/aligned-sized/src/lib.rs @@ -6,7 +6,7 @@ //! Future plans: //! //! * Ensuring that the struct is aligned, adding padding fields when -//! neccessary. +//! necessary. //! //! # Motivation //! diff --git a/program-libs/array-map/.cargo-rdme.toml b/program-libs/array-map/.cargo-rdme.toml new file mode 100644 index 0000000000..8ce9d3a73e --- /dev/null +++ b/program-libs/array-map/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-array-map" +heading-base-level = 0 diff --git a/program-libs/array-map/Cargo.toml b/program-libs/array-map/Cargo.toml index a02da0afef..aa8f562ca8 100644 --- a/program-libs/array-map/Cargo.toml +++ b/program-libs/array-map/Cargo.toml @@ -2,6 +2,7 @@ name = "light-array-map" version = "0.2.0" description = "Generic array-backed map with O(n) lookup for small collections" +readme = "README.md" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" edition = "2021" diff --git a/program-libs/array-map/README.md b/program-libs/array-map/README.md new file mode 100644 index 0000000000..6c33ef4707 --- /dev/null +++ b/program-libs/array-map/README.md @@ -0,0 +1,14 @@ + + +# light-array-map + +Generic array-backed map with O(n) lookup for small collections. +Built on `tinyvec::ArrayVec`. Tracks insertion order and last updated index. + +| Type | Description | +|------|-------------| +| [`ArrayMap`] | Fixed-capacity map keyed by `K` with O(n) scan | +| [`ArrayMapError`] | Capacity exceeded or index out of bounds | +| [`pubkey_eq`] | Compares two `[u8; 32]` keys via 4x `u64` reads | + + diff --git a/program-libs/array-map/src/lib.rs b/program-libs/array-map/src/lib.rs index 184381f011..7569683714 100644 --- a/program-libs/array-map/src/lib.rs +++ b/program-libs/array-map/src/lib.rs @@ -1,3 +1,14 @@ +//! # light-array-map +//! +//! Generic array-backed map with O(n) lookup for small collections. +//! Built on `tinyvec::ArrayVec`. Tracks insertion order and last updated index. +//! +//! | Type | Description | +//! |------|-------------| +//! | [`ArrayMap`] | Fixed-capacity map keyed by `K` with O(n) scan | +//! | [`ArrayMapError`] | Capacity exceeded or index out of bounds | +//! | [`pubkey_eq`] | Compares two `[u8; 32]` keys via 4x `u64` reads | + #![no_std] use core::ptr::read_unaligned; diff --git a/program-libs/batched-merkle-tree/.cargo-rdme.toml b/program-libs/batched-merkle-tree/.cargo-rdme.toml new file mode 100644 index 0000000000..9a9c508126 --- /dev/null +++ b/program-libs/batched-merkle-tree/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-batched-merkle-tree" +heading-base-level = 0 diff --git a/program-libs/batched-merkle-tree/Cargo.toml b/program-libs/batched-merkle-tree/Cargo.toml index 7eabdd9935..530759a0f5 100644 --- a/program-libs/batched-merkle-tree/Cargo.toml +++ b/program-libs/batched-merkle-tree/Cargo.toml @@ -2,6 +2,7 @@ name = "light-batched-merkle-tree" version = "0.9.0" description = "Batch Merkle tree implementation." +readme = "README.md" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" edition = "2021" diff --git a/program-libs/batched-merkle-tree/README.md b/program-libs/batched-merkle-tree/README.md new file mode 100644 index 0000000000..126d21ab75 --- /dev/null +++ b/program-libs/batched-merkle-tree/README.md @@ -0,0 +1,174 @@ + + +# light-batched-merkle-tree + +The crate provides batched Merkle tree +implementations for the account compression program. +Instead of updating trees one leaf at a time, this library batches +multiple insertions and updates them with zero-knowledge proofs (ZKPs), +enabling efficient on-chain verification. Trees maintain a cyclic root +history for validity proofs, and use bloom filters for non-inclusion +proofs while batches are being filled. + +There are two tree types: **state trees** (two accounts tree account +(input queue, tree metadata, roots), output queue account) for compressed +accounts, and **address trees** (one account that contains the address queue, +tree metadata, roots) for address registration. + +| Module | Description | +|--------|-------------| +| [`batch`] | Batch append and update operations | +| [`merkle_tree`] | Batched Merkle tree account struct | +| [`queue`] | Queue account for batched leaves | +| [`queue_batch_metadata`] | Metadata for queue batches | +| [`initialize_state_tree`] | Initialize a batched state tree | +| [`initialize_address_tree`] | Initialize a batched address tree | +| [`rollover_state_tree`] | Roll over a full state tree | +| [`rollover_address_tree`] | Roll over a full address tree | +| [`merkle_tree_metadata`] | Tree and queue metadata structs | +| [`errors`] | Error types for batch operations | + +## Accounts + +### Account Types + +- **[TREE_ACCOUNT.md](TREE_ACCOUNT.md)** - BatchedMerkleTreeAccount (state and address trees) +- **[QUEUE_ACCOUNT.md](QUEUE_ACCOUNT.md)** - BatchedQueueAccount (output queue for state trees) + +### Overview + +The batched merkle tree library uses two main Solana account types: + +**BatchedMerkleTreeAccount:** +The main tree account storing tree roots, root history, and integrated input queue (bloom filters + hash chains for nullifiers or addresses). Used for both state trees and address trees. + +**Details:** [TREE_ACCOUNT.md](TREE_ACCOUNT.md) + +**BatchedQueueAccount:** +Output queue account for state trees that temporarily stores compressed account hashes before tree insertion. Enables immediate spending via proof-by-index. + +**Details:** [QUEUE_ACCOUNT.md](QUEUE_ACCOUNT.md) + +### State Trees vs Address Trees + +**State Trees (2 accounts):** +- `BatchedMerkleTreeAccount` with integrated input queue (for nullifiers) +- Separate `BatchedQueueAccount` for output operations (appending new compressed accounts) + +**Address Trees (1 account):** +- `BatchedMerkleTreeAccount` with integrated input queue (for addresses) +- No separate output queue + +## Operations + +### Initialization +- **[INITIALIZE_STATE_TREE.md](INITIALIZE_STATE_TREE.md)** - Create state tree + output queue pair (2 solana accounts) + - Source: [`src/initialize_state_tree.rs`](../src/initialize_state_tree.rs) + +- **[INITIALIZE_ADDRESS_TREE.md](INITIALIZE_ADDRESS_TREE.md)** - Create address tree with integrated queue (1 solana account) + - Source: [`src/initialize_address_tree.rs`](../src/initialize_address_tree.rs) + +### Queue Insertion Operations +- **[INSERT_OUTPUT_QUEUE.md](INSERT_OUTPUT_QUEUE.md)** - Insert compressed account hash into output queue (state tree) + - Source: [`src/queue.rs`](../src/queue.rs) - `BatchedQueueAccount::insert_into_current_batch` + +- **[INSERT_INPUT_QUEUE.md](INSERT_INPUT_QUEUE.md)** - Insert nullifiers into input queue (state tree) + - Source: [`src/merkle_tree.rs`](../src/merkle_tree.rs) - `BatchedMerkleTreeAccount::insert_nullifier_into_queue` + +- **[INSERT_ADDRESS_QUEUE.md](INSERT_ADDRESS_QUEUE.md)** - Insert addresses into address queue + - Source: [`src/merkle_tree.rs`](../src/merkle_tree.rs) - `BatchedMerkleTreeAccount::insert_address_into_queue` + +### Tree Update Operations +- **[UPDATE_FROM_OUTPUT_QUEUE.md](UPDATE_FROM_OUTPUT_QUEUE.md)** - Batch append with ZKP verification + - Source: [`src/merkle_tree.rs`](../src/merkle_tree.rs) - `BatchedMerkleTreeAccount::update_tree_from_output_queue_account` + +- **[UPDATE_FROM_INPUT_QUEUE.md](UPDATE_FROM_INPUT_QUEUE.md)** - Batch nullify/address updates with ZKP + - Source: [`src/merkle_tree.rs`](../src/merkle_tree.rs) - `update_tree_from_input_queue`, `update_tree_from_address_queue` + +## Key Concepts + +**Batching System:** Trees use 2 alternating batches. While one batch is being filled, the previous batch can be updated into the tree with a ZKP. + +**ZKP Batches:** Each batch is divided into smaller ZKP batches (`batch_size / zkp_batch_size`). Trees are updated incrementally by ZKP batch. + +**Bloom Filters:** Input queues (nullifier queue for state trees, address queue for address trees) use bloom filters for non-inclusion proofs. While a batch is filling, values are inserted into the bloom filter. After the batch is fully inserted into the tree and the next batch is 50% full, the bloom filter is zeroed to prevent false positives. Output queues do not use bloom filters. + +**Value Vecs:** Output queues store the actual compressed account hashes in value vectors (one per batch). Values can be accessed by leaf index even before they're inserted into the tree, enabling immediate spending of newly created compressed accounts. + +**Hash Chains:** Each ZKP batch has a hash chain storing the Poseidon hash of all values in that ZKP batch. These hash chains are used as public inputs for ZKP verification. + +**ZKP Verification:** Tree updates require zero-knowledge proofs proving the correctness of batch operations (old root + queue values → new root). Public inputs: old root, new root, hash chain (commitment to queue elements), and for appends: start_index (output queue) or next_index (address queue). + +**Root History:** Trees maintain a cyclic buffer of recent roots (default: 200). This enables validity proofs for recently spent compressed accounts even as the tree continues to update. + +**Rollover:** When a tree reaches capacity (2^height leaves), it must be replaced with a new tree. The rollover process creates a new tree and marks the old tree as rolled over, preserving the old tree's roots for ongoing validity proofs. A rollover can be performed once the rollover threshold is met (default: 95% full). + +**State vs Address Trees:** +- **State trees** have a separate `BatchedQueueAccount` for output operations (appending new leaves). Input operations (nullifying) use the integrated input queue on the tree account. +- **Address trees** have only an integrated input queue on the tree account - no separate output queue. + +## ZKP Verification + +Batch update operations require zero-knowledge proofs generated by the Light Protocol prover: + +- **Prover Server:** `prover/server/` - Generates ZK proofs for batch operations +- **Prover Client:** `prover/client/` - Client libraries for requesting proofs +- **Batch Update Circuits:** `prover/server/prover/v2/` - Circuit definitions for batch append, batch update (nullify), and batch address append operations + +## Dependencies + +This crate relies on several Light Protocol libraries: + +- **`light-bloom-filter`** - Bloom filter implementation for non-inclusion proofs +- **`light-hasher`** - Poseidon hash implementation for hash chains and tree operations +- **`light-verifier`** - ZKP verification for batch updates +- **`light-zero-copy`** - Zero-copy serialization for efficient account data access +- **`light-merkle-tree-metadata`** - Shared metadata structures for merkle trees +- **`light-compressed-account`** - Compressed account types and utilities +- **`light-account-checks`** - Account validation and discriminator checks + +## Testing and Reference Implementations + +**IndexedMerkleTree Reference Implementation:** +- **`light-merkle-tree-reference`** - Reference implementation of indexed Merkle trees (dev dependency) +- Source: `program-tests/merkle-tree/src/indexed.rs` - Canonical IndexedMerkleTree implementation used for generating constants and testing +- Used to generate constants like `ADDRESS_TREE_INIT_ROOT_40` in [`src/constants.rs`](../src/constants.rs) +- Initializes address trees with a single leaf: `H(0, HIGHEST_ADDRESS_PLUS_ONE)` + +## Source Code Structure + +**Core Account Types:** +- [`src/merkle_tree.rs`](../src/merkle_tree.rs) - `BatchedMerkleTreeAccount` (prove inclusion, nullify existing state, create new addresses) +- [`src/queue.rs`](../src/queue.rs) - `BatchedQueueAccount` (add new state (transaction outputs)) +- [`src/batch.rs`](../src/batch.rs) - `Batch` state machine (Fill → Full → Inserted) +- [`src/queue_batch_metadata.rs`](../src/queue_batch_metadata.rs) - `QueueBatches` metadata + +**Metadata and Configuration:** +- [`src/merkle_tree_metadata.rs`](../src/merkle_tree_metadata.rs) - `BatchedMerkleTreeMetadata` and account size calculations +- [`src/constants.rs`](../src/constants.rs) - Default configuration values + +**ZKP Infrastructure:** +- `prover/server/` - Prover server that generates ZK proofs for batch operations +- `prover/client/` - Client libraries for requesting proofs +- `prover/server/prover/v2/` - Batch update circuit definitions (append, nullify, address append) + +**Initialization:** +- [`src/initialize_state_tree.rs`](../src/initialize_state_tree.rs) - State tree initialization +- [`src/initialize_address_tree.rs`](../src/initialize_address_tree.rs) - Address tree initialization +- [`src/rollover_state_tree.rs`](../src/rollover_state_tree.rs) - State tree rollover +- [`src/rollover_address_tree.rs`](../src/rollover_address_tree.rs) - Address tree rollover + +**Errors:** +- [`src/errors.rs`](../src/errors.rs) - `BatchedMerkleTreeError` enum with all error types + +## Error Codes + +All errors are defined in [`src/errors.rs`](../src/errors.rs) and map to u32 error codes (14301-14312 range): +- `BatchNotReady` (14301) - Batch is not ready to be inserted +- `BatchAlreadyInserted` (14302) - Batch is already inserted +- `TreeIsFull` (14310) - Batched Merkle tree reached capacity +- `NonInclusionCheckFailed` (14311) - Value exists in bloom filter +- `BloomFilterNotZeroed` (14312) - Bloom filter must be zeroed before reuse +- Additional errors from underlying libraries (hasher, zero-copy, verifier, etc.) + + diff --git a/program-libs/batched-merkle-tree/src/lib.rs b/program-libs/batched-merkle-tree/src/lib.rs index 429cad16a9..50e4810920 100644 --- a/program-libs/batched-merkle-tree/src/lib.rs +++ b/program-libs/batched-merkle-tree/src/lib.rs @@ -1,3 +1,174 @@ +//! # light-batched-merkle-tree +//! +//! The crate provides batched Merkle tree +//! implementations for the account compression program. +//! Instead of updating trees one leaf at a time, this library batches +//! multiple insertions and updates them with zero-knowledge proofs (ZKPs), +//! enabling efficient on-chain verification. Trees maintain a cyclic root +//! history for validity proofs, and use bloom filters for non-inclusion +//! proofs while batches are being filled. +//! +//! There are two tree types: **state trees** (two accounts tree account +//! (input queue, tree metadata, roots), output queue account) for compressed +//! accounts, and **address trees** (one account that contains the address queue, +//! tree metadata, roots) for address registration. +//! +//! | Module | Description | +//! |--------|-------------| +//! | [`batch`] | Batch append and update operations | +//! | [`merkle_tree`] | Batched Merkle tree account struct | +//! | [`queue`] | Queue account for batched leaves | +//! | [`queue_batch_metadata`] | Metadata for queue batches | +//! | [`initialize_state_tree`] | Initialize a batched state tree | +//! | [`initialize_address_tree`] | Initialize a batched address tree | +//! | [`rollover_state_tree`] | Roll over a full state tree | +//! | [`rollover_address_tree`] | Roll over a full address tree | +//! | [`merkle_tree_metadata`] | Tree and queue metadata structs | +//! | [`errors`] | Error types for batch operations | +//! +//! ## Accounts +//! +//! ### Account Types +//! +//! - **[TREE_ACCOUNT.md](TREE_ACCOUNT.md)** - BatchedMerkleTreeAccount (state and address trees) +//! - **[QUEUE_ACCOUNT.md](QUEUE_ACCOUNT.md)** - BatchedQueueAccount (output queue for state trees) +//! +//! ### Overview +//! +//! The batched merkle tree library uses two main Solana account types: +//! +//! **BatchedMerkleTreeAccount:** +//! The main tree account storing tree roots, root history, and integrated input queue (bloom filters + hash chains for nullifiers or addresses). Used for both state trees and address trees. +//! +//! **Details:** [TREE_ACCOUNT.md](TREE_ACCOUNT.md) +//! +//! **BatchedQueueAccount:** +//! Output queue account for state trees that temporarily stores compressed account hashes before tree insertion. Enables immediate spending via proof-by-index. +//! +//! **Details:** [QUEUE_ACCOUNT.md](QUEUE_ACCOUNT.md) +//! +//! ### State Trees vs Address Trees +//! +//! **State Trees (2 accounts):** +//! - `BatchedMerkleTreeAccount` with integrated input queue (for nullifiers) +//! - Separate `BatchedQueueAccount` for output operations (appending new compressed accounts) +//! +//! **Address Trees (1 account):** +//! - `BatchedMerkleTreeAccount` with integrated input queue (for addresses) +//! - No separate output queue +//! +//! ## Operations +//! +//! ### Initialization +//! - **[INITIALIZE_STATE_TREE.md](INITIALIZE_STATE_TREE.md)** - Create state tree + output queue pair (2 solana accounts) +//! - Source: [`src/initialize_state_tree.rs`](../src/initialize_state_tree.rs) +//! +//! - **[INITIALIZE_ADDRESS_TREE.md](INITIALIZE_ADDRESS_TREE.md)** - Create address tree with integrated queue (1 solana account) +//! - Source: [`src/initialize_address_tree.rs`](../src/initialize_address_tree.rs) +//! +//! ### Queue Insertion Operations +//! - **[INSERT_OUTPUT_QUEUE.md](INSERT_OUTPUT_QUEUE.md)** - Insert compressed account hash into output queue (state tree) +//! - Source: [`src/queue.rs`](../src/queue.rs) - `BatchedQueueAccount::insert_into_current_batch` +//! +//! - **[INSERT_INPUT_QUEUE.md](INSERT_INPUT_QUEUE.md)** - Insert nullifiers into input queue (state tree) +//! - Source: [`src/merkle_tree.rs`](../src/merkle_tree.rs) - `BatchedMerkleTreeAccount::insert_nullifier_into_queue` +//! +//! - **[INSERT_ADDRESS_QUEUE.md](INSERT_ADDRESS_QUEUE.md)** - Insert addresses into address queue +//! - Source: [`src/merkle_tree.rs`](../src/merkle_tree.rs) - `BatchedMerkleTreeAccount::insert_address_into_queue` +//! +//! ### Tree Update Operations +//! - **[UPDATE_FROM_OUTPUT_QUEUE.md](UPDATE_FROM_OUTPUT_QUEUE.md)** - Batch append with ZKP verification +//! - Source: [`src/merkle_tree.rs`](../src/merkle_tree.rs) - `BatchedMerkleTreeAccount::update_tree_from_output_queue_account` +//! +//! - **[UPDATE_FROM_INPUT_QUEUE.md](UPDATE_FROM_INPUT_QUEUE.md)** - Batch nullify/address updates with ZKP +//! - Source: [`src/merkle_tree.rs`](../src/merkle_tree.rs) - `update_tree_from_input_queue`, `update_tree_from_address_queue` +//! +//! ## Key Concepts +//! +//! **Batching System:** Trees use 2 alternating batches. While one batch is being filled, the previous batch can be updated into the tree with a ZKP. +//! +//! **ZKP Batches:** Each batch is divided into smaller ZKP batches (`batch_size / zkp_batch_size`). Trees are updated incrementally by ZKP batch. +//! +//! **Bloom Filters:** Input queues (nullifier queue for state trees, address queue for address trees) use bloom filters for non-inclusion proofs. While a batch is filling, values are inserted into the bloom filter. After the batch is fully inserted into the tree and the next batch is 50% full, the bloom filter is zeroed to prevent false positives. Output queues do not use bloom filters. +//! +//! **Value Vecs:** Output queues store the actual compressed account hashes in value vectors (one per batch). Values can be accessed by leaf index even before they're inserted into the tree, enabling immediate spending of newly created compressed accounts. +//! +//! **Hash Chains:** Each ZKP batch has a hash chain storing the Poseidon hash of all values in that ZKP batch. These hash chains are used as public inputs for ZKP verification. +//! +//! **ZKP Verification:** Tree updates require zero-knowledge proofs proving the correctness of batch operations (old root + queue values → new root). Public inputs: old root, new root, hash chain (commitment to queue elements), and for appends: start_index (output queue) or next_index (address queue). +//! +//! **Root History:** Trees maintain a cyclic buffer of recent roots (default: 200). This enables validity proofs for recently spent compressed accounts even as the tree continues to update. +//! +//! **Rollover:** When a tree reaches capacity (2^height leaves), it must be replaced with a new tree. The rollover process creates a new tree and marks the old tree as rolled over, preserving the old tree's roots for ongoing validity proofs. A rollover can be performed once the rollover threshold is met (default: 95% full). +//! +//! **State vs Address Trees:** +//! - **State trees** have a separate `BatchedQueueAccount` for output operations (appending new leaves). Input operations (nullifying) use the integrated input queue on the tree account. +//! - **Address trees** have only an integrated input queue on the tree account - no separate output queue. +//! +//! ## ZKP Verification +//! +//! Batch update operations require zero-knowledge proofs generated by the Light Protocol prover: +//! +//! - **Prover Server:** `prover/server/` - Generates ZK proofs for batch operations +//! - **Prover Client:** `prover/client/` - Client libraries for requesting proofs +//! - **Batch Update Circuits:** `prover/server/prover/v2/` - Circuit definitions for batch append, batch update (nullify), and batch address append operations +//! +//! ## Dependencies +//! +//! This crate relies on several Light Protocol libraries: +//! +//! - **`light-bloom-filter`** - Bloom filter implementation for non-inclusion proofs +//! - **`light-hasher`** - Poseidon hash implementation for hash chains and tree operations +//! - **`light-verifier`** - ZKP verification for batch updates +//! - **`light-zero-copy`** - Zero-copy serialization for efficient account data access +//! - **`light-merkle-tree-metadata`** - Shared metadata structures for merkle trees +//! - **`light-compressed-account`** - Compressed account types and utilities +//! - **`light-account-checks`** - Account validation and discriminator checks +//! +//! ## Testing and Reference Implementations +//! +//! **IndexedMerkleTree Reference Implementation:** +//! - **`light-merkle-tree-reference`** - Reference implementation of indexed Merkle trees (dev dependency) +//! - Source: `program-tests/merkle-tree/src/indexed.rs` - Canonical IndexedMerkleTree implementation used for generating constants and testing +//! - Used to generate constants like `ADDRESS_TREE_INIT_ROOT_40` in [`src/constants.rs`](../src/constants.rs) +//! - Initializes address trees with a single leaf: `H(0, HIGHEST_ADDRESS_PLUS_ONE)` +//! +//! ## Source Code Structure +//! +//! **Core Account Types:** +//! - [`src/merkle_tree.rs`](../src/merkle_tree.rs) - `BatchedMerkleTreeAccount` (prove inclusion, nullify existing state, create new addresses) +//! - [`src/queue.rs`](../src/queue.rs) - `BatchedQueueAccount` (add new state (transaction outputs)) +//! - [`src/batch.rs`](../src/batch.rs) - `Batch` state machine (Fill → Full → Inserted) +//! - [`src/queue_batch_metadata.rs`](../src/queue_batch_metadata.rs) - `QueueBatches` metadata +//! +//! **Metadata and Configuration:** +//! - [`src/merkle_tree_metadata.rs`](../src/merkle_tree_metadata.rs) - `BatchedMerkleTreeMetadata` and account size calculations +//! - [`src/constants.rs`](../src/constants.rs) - Default configuration values +//! +//! **ZKP Infrastructure:** +//! - `prover/server/` - Prover server that generates ZK proofs for batch operations +//! - `prover/client/` - Client libraries for requesting proofs +//! - `prover/server/prover/v2/` - Batch update circuit definitions (append, nullify, address append) +//! +//! **Initialization:** +//! - [`src/initialize_state_tree.rs`](../src/initialize_state_tree.rs) - State tree initialization +//! - [`src/initialize_address_tree.rs`](../src/initialize_address_tree.rs) - Address tree initialization +//! - [`src/rollover_state_tree.rs`](../src/rollover_state_tree.rs) - State tree rollover +//! - [`src/rollover_address_tree.rs`](../src/rollover_address_tree.rs) - Address tree rollover +//! +//! **Errors:** +//! - [`src/errors.rs`](../src/errors.rs) - `BatchedMerkleTreeError` enum with all error types +//! +//! ## Error Codes +//! +//! All errors are defined in [`src/errors.rs`](../src/errors.rs) and map to u32 error codes (14301-14312 range): +//! - `BatchNotReady` (14301) - Batch is not ready to be inserted +//! - `BatchAlreadyInserted` (14302) - Batch is already inserted +//! - `TreeIsFull` (14310) - Batched Merkle tree reached capacity +//! - `NonInclusionCheckFailed` (14311) - Value exists in bloom filter +//! - `BloomFilterNotZeroed` (14312) - Bloom filter must be zeroed before reuse +//! - Additional errors from underlying libraries (hasher, zero-copy, verifier, etc.) + #![allow(unexpected_cfgs)] pub mod batch; pub mod constants; diff --git a/program-libs/bloom-filter/.cargo-rdme.toml b/program-libs/bloom-filter/.cargo-rdme.toml new file mode 100644 index 0000000000..9b8369d3f7 --- /dev/null +++ b/program-libs/bloom-filter/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-bloom-filter" +heading-base-level = 0 diff --git a/program-libs/bloom-filter/Cargo.toml b/program-libs/bloom-filter/Cargo.toml index 963a27b735..237458cabd 100644 --- a/program-libs/bloom-filter/Cargo.toml +++ b/program-libs/bloom-filter/Cargo.toml @@ -2,6 +2,7 @@ name = "light-bloom-filter" version = "0.6.0" description = "Experimental bloom filter." +readme = "README.md" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" edition = "2021" diff --git a/program-libs/bloom-filter/README.md b/program-libs/bloom-filter/README.md new file mode 100644 index 0000000000..3e4710200d --- /dev/null +++ b/program-libs/bloom-filter/README.md @@ -0,0 +1,15 @@ + + +# light-bloom-filter + +Experimental bloom filter using keccak hashing. + +| Type | Description | +|------|-------------| +| [`BloomFilter`] | Probabilistic set with `insert` and `contains` | +| [`BloomFilterError`] | Full or invalid store capacity | +| [`BloomFilter::calculate_bloom_filter_size`] | Optimal bit count for given `n` and `p` | +| [`BloomFilter::calculate_optimal_hash_functions`] | Optimal `k` for given `n` and `m` | +| [`BloomFilter::probe_index_keccak`] | Keccak-based probe index for a value | + + diff --git a/program-libs/bloom-filter/src/lib.rs b/program-libs/bloom-filter/src/lib.rs index d5375bd82e..389c70086e 100644 --- a/program-libs/bloom-filter/src/lib.rs +++ b/program-libs/bloom-filter/src/lib.rs @@ -1,3 +1,15 @@ +//! # light-bloom-filter +//! +//! Experimental bloom filter using keccak hashing. +//! +//! | Type | Description | +//! |------|-------------| +//! | [`BloomFilter`] | Probabilistic set with `insert` and `contains` | +//! | [`BloomFilterError`] | Full or invalid store capacity | +//! | [`BloomFilter::calculate_bloom_filter_size`] | Optimal bit count for given `n` and `p` | +//! | [`BloomFilter::calculate_optimal_hash_functions`] | Optimal `k` for given `n` and `m` | +//! | [`BloomFilter::probe_index_keccak`] | Keccak-based probe index for a value | + use std::f64::consts::LN_2; use thiserror::Error; diff --git a/program-libs/compressed-account/.cargo-rdme.toml b/program-libs/compressed-account/.cargo-rdme.toml new file mode 100644 index 0000000000..66c1fe32f6 --- /dev/null +++ b/program-libs/compressed-account/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-compressed-account" +heading-base-level = 0 diff --git a/program-libs/compressed-account/Cargo.toml b/program-libs/compressed-account/Cargo.toml index 4295a071de..a1630189aa 100644 --- a/program-libs/compressed-account/Cargo.toml +++ b/program-libs/compressed-account/Cargo.toml @@ -2,6 +2,7 @@ name = "light-compressed-account" version = "0.9.0" description = "Compressed account struct and common utility functions used in Light Protocol." +readme = "README.md" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" edition = "2021" diff --git a/program-libs/compressed-account/README.md b/program-libs/compressed-account/README.md new file mode 100644 index 0000000000..1b8af703e6 --- /dev/null +++ b/program-libs/compressed-account/README.md @@ -0,0 +1,22 @@ + + +# light-compressed-account + +Compressed account struct and utility types for Light Protocol. + +| Type | Description | +|------|-------------| +| [`CompressedAccountError`] | Error codes 12001–12025 for account operations | +| [`QueueType`] | Nullifier, address, and state queue variants | +| [`TreeType`] | State and address tree version variants | +| [`CpiSigner`] | Program ID, CPI signer pubkey, and bump | +| [`address`] | Address derivation and seed structs | +| [`compressed_account`] | Core compressed account struct | +| [`constants`] | Program IDs and account discriminators as byte arrays | +| [`discriminators`] | Instruction discriminators for `invoke`, `invoke_cpi`, and queue operations | +| [`instruction_data`] | Instruction data types and proof structs | +| [`nullifier`] | Nullifier computation | +| [`pubkey`] | `Pubkey` struct (re-exported at root) and `AsPubkey` conversion trait | +| [`tx_hash`] | Transaction hash computation | + + diff --git a/program-libs/compressed-account/src/lib.rs b/program-libs/compressed-account/src/lib.rs index 02a78c900c..5c0768f2db 100644 --- a/program-libs/compressed-account/src/lib.rs +++ b/program-libs/compressed-account/src/lib.rs @@ -1,3 +1,22 @@ +//! # light-compressed-account +//! +//! Compressed account struct and utility types for Light Protocol. +//! +//! | Type | Description | +//! |------|-------------| +//! | [`CompressedAccountError`] | Error codes 12001–12025 for account operations | +//! | [`QueueType`] | Nullifier, address, and state queue variants | +//! | [`TreeType`] | State and address tree version variants | +//! | [`CpiSigner`] | Program ID, CPI signer pubkey, and bump | +//! | [`address`] | Address derivation and seed structs | +//! | [`compressed_account`] | Core compressed account struct | +//! | [`constants`] | Program IDs and account discriminators as byte arrays | +//! | [`discriminators`] | Instruction discriminators for `invoke`, `invoke_cpi`, and queue operations | +//! | [`instruction_data`] | Instruction data types and proof structs | +//! | [`nullifier`] | Nullifier computation | +//! | [`pubkey`] | `Pubkey` struct (re-exported at root) and `AsPubkey` conversion trait | +//! | [`tx_hash`] | Transaction hash computation | + #![allow(unexpected_cfgs)] #![cfg_attr(not(feature = "std"), no_std)] diff --git a/program-libs/compressible/.cargo-rdme.toml b/program-libs/compressible/.cargo-rdme.toml new file mode 100644 index 0000000000..6149a451ab --- /dev/null +++ b/program-libs/compressible/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-compressible" +heading-base-level = 0 diff --git a/program-libs/compressible/Cargo.toml b/program-libs/compressible/Cargo.toml index 67b429a05b..b817f7bed1 100644 --- a/program-libs/compressible/Cargo.toml +++ b/program-libs/compressible/Cargo.toml @@ -3,6 +3,7 @@ name = "light-compressible" version = "0.4.0" edition = "2021" description = "Light Protocol compressible data structures" +readme = "README.md" license = "MIT" [features] diff --git a/program-libs/compressible/README.md b/program-libs/compressible/README.md new file mode 100644 index 0000000000..9b9a6a7a80 --- /dev/null +++ b/program-libs/compressible/README.md @@ -0,0 +1,23 @@ + + +# light-compressible + +Compressible account lifecycle for accounts with sponsored rent-exemption. +The program pays the rent exemption for the account. Transaction fee payers +bump a virtual rent balance when writing to the account, which keeps the +account "hot". "Cold" accounts virtual rent balance below threshold +(eg 24h without write bump) get auto-compressed. The cold account's state +is cryptographically preserved on the Solana ledger. Users can load a +cold account into hot state in-flight when using the account again. + +| Type | Description | +|------|-------------| +| [`CompressionInfo`](compression_info::CompressionInfo) | Rent state, authorities, and compression config per account | +| [`CompressibleConfig`](config::CompressibleConfig) | Program-level config: rent sponsor, authorities, address space | +| [`CreateAccountsProof`] | Validity proof and tree info for account init | +| [`RentConfig`](rent::RentConfig) | Rent function parameters for compression eligibility | +| [`compression_info`] | `is_compressible`, `claim`, and top-up logic | +| [`registry_instructions`] | Instructions for the compression registry | +| [`rent`] | Epoch-based rent calculation and claim amounts | + + diff --git a/program-libs/compressible/src/lib.rs b/program-libs/compressible/src/lib.rs index 7382b1c400..19f758a86f 100644 --- a/program-libs/compressible/src/lib.rs +++ b/program-libs/compressible/src/lib.rs @@ -1,3 +1,24 @@ +//! # light-compressible +//! +//! Compressible account lifecycle for accounts with sponsored rent-exemption. +//! The program pays the rent exemption for the account. Transaction fee payers +//! bump a virtual rent balance when writing to the account, which keeps the +//! account "hot". "Cold" accounts virtual rent balance below threshold +//! (eg 24h without write bump) get auto-compressed. The cold account's state +//! is cryptographically preserved on the Solana ledger. Users can load a +//! cold account into hot state in-flight when using the account again. + +//! +//! | Type | Description | +//! |------|-------------| +//! | [`CompressionInfo`](compression_info::CompressionInfo) | Rent state, authorities, and compression config per account | +//! | [`CompressibleConfig`](config::CompressibleConfig) | Program-level config: rent sponsor, authorities, address space | +//! | [`CreateAccountsProof`] | Validity proof and tree info for account init | +//! | [`RentConfig`](rent::RentConfig) | Rent function parameters for compression eligibility | +//! | [`compression_info`] | `is_compressible`, `claim`, and top-up logic | +//! | [`registry_instructions`] | Instructions for the compression registry | +//! | [`rent`] | Epoch-based rent calculation and claim amounts | + pub mod compression_info; pub mod config; pub mod error; diff --git a/program-libs/concurrent-merkle-tree/.cargo-rdme.toml b/program-libs/concurrent-merkle-tree/.cargo-rdme.toml new file mode 100644 index 0000000000..0fd66605da --- /dev/null +++ b/program-libs/concurrent-merkle-tree/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-concurrent-merkle-tree" +heading-base-level = 0 diff --git a/program-libs/concurrent-merkle-tree/Cargo.toml b/program-libs/concurrent-merkle-tree/Cargo.toml index 80d1a8a5db..2094b5765c 100644 --- a/program-libs/concurrent-merkle-tree/Cargo.toml +++ b/program-libs/concurrent-merkle-tree/Cargo.toml @@ -3,6 +3,7 @@ name = "light-concurrent-merkle-tree" version = "5.0.0" edition = "2021" description = "Concurrent Merkle tree implementation" +readme = "README.md" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" diff --git a/program-libs/concurrent-merkle-tree/README.md b/program-libs/concurrent-merkle-tree/README.md new file mode 100644 index 0000000000..3ee63946b0 --- /dev/null +++ b/program-libs/concurrent-merkle-tree/README.md @@ -0,0 +1,18 @@ + + +# light-concurrent-merkle-tree + +Concurrent Merkle tree that accepts multiple leaf updates +without invalidating other in-flight proofs. + +| Type | Description | +|------|-------------| +| [`ConcurrentMerkleTree`] | Append, update, and validate leaves concurrently | +| [`ConcurrentMerkleTree26`] | Type alias for height-26 trees | +| [`changelog`] | Changelog entries for concurrent proof patching | +| [`errors`] | `ConcurrentMerkleTreeError` variants | +| [`hash`] | `compute_parent_node` and `compute_root` | +| [`zero_copy`] | Zero-copy deserialization from account data | +| [`event`] | Changelog event for indexers | + + diff --git a/program-libs/concurrent-merkle-tree/src/lib.rs b/program-libs/concurrent-merkle-tree/src/lib.rs index a845b8986d..18e9cb6f94 100644 --- a/program-libs/concurrent-merkle-tree/src/lib.rs +++ b/program-libs/concurrent-merkle-tree/src/lib.rs @@ -1,3 +1,18 @@ +//! # light-concurrent-merkle-tree +//! +//! Concurrent Merkle tree that accepts multiple leaf updates +//! without invalidating other in-flight proofs. +//! +//! | Type | Description | +//! |------|-------------| +//! | [`ConcurrentMerkleTree`] | Append, update, and validate leaves concurrently | +//! | [`ConcurrentMerkleTree26`] | Type alias for height-26 trees | +//! | [`changelog`] | Changelog entries for concurrent proof patching | +//! | [`errors`] | `ConcurrentMerkleTreeError` variants | +//! | [`hash`] | `compute_parent_node` and `compute_root` | +//! | [`zero_copy`] | Zero-copy deserialization from account data | +//! | [`event`] | Changelog event for indexers | + use std::{ alloc::{self, handle_alloc_error, Layout}, iter::Skip, diff --git a/program-libs/hash-set/.cargo-rdme.toml b/program-libs/hash-set/.cargo-rdme.toml new file mode 100644 index 0000000000..72f7ec39fd --- /dev/null +++ b/program-libs/hash-set/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-hash-set" +heading-base-level = 0 diff --git a/program-libs/hash-set/Cargo.toml b/program-libs/hash-set/Cargo.toml index 4152cefe71..d330764057 100644 --- a/program-libs/hash-set/Cargo.toml +++ b/program-libs/hash-set/Cargo.toml @@ -2,6 +2,7 @@ name = "light-hash-set" version = "4.0.0" description = "Hash set which can be stored on a Solana account" +readme = "README.md" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" edition = "2021" diff --git a/program-libs/hash-set/README.md b/program-libs/hash-set/README.md new file mode 100644 index 0000000000..6cd6be3f2d --- /dev/null +++ b/program-libs/hash-set/README.md @@ -0,0 +1,16 @@ + + +# light-hash-set + +Hash set stored on a Solana account. Uses quadratic probing +with sequence-number-based expiry for element invalidation. + +| Type | Description | +|------|-------------| +| [`HashSet`] | Insert, find, contains, and mark elements by sequence number | +| [`HashSetCell`] | Cell storing a 32-byte value and optional sequence number | +| [`HashSetError`] | Full, duplicate, not found, and overflow errors | +| [`HashSetIterator`] | Iterates over occupied cells | +| [`zero_copy`] | Zero-copy deserialization from account data | + + diff --git a/program-libs/hash-set/src/lib.rs b/program-libs/hash-set/src/lib.rs index 508133e83a..8e5ac67ec1 100644 --- a/program-libs/hash-set/src/lib.rs +++ b/program-libs/hash-set/src/lib.rs @@ -1,3 +1,16 @@ +//! # light-hash-set +//! +//! Hash set stored on a Solana account. Uses quadratic probing +//! with sequence-number-based expiry for element invalidation. +//! +//! | Type | Description | +//! |------|-------------| +//! | [`HashSet`] | Insert, find, contains, and mark elements by sequence number | +//! | [`HashSetCell`] | Cell storing a 32-byte value and optional sequence number | +//! | [`HashSetError`] | Full, duplicate, not found, and overflow errors | +//! | [`HashSetIterator`] | Iterates over occupied cells | +//! | [`zero_copy`] | Zero-copy deserialization from account data | + use std::{ alloc::{self, handle_alloc_error, Layout}, cmp::Ordering, diff --git a/program-libs/hasher/.cargo-rdme.toml b/program-libs/hasher/.cargo-rdme.toml new file mode 100644 index 0000000000..a5812f740a --- /dev/null +++ b/program-libs/hasher/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-hasher" +heading-base-level = 0 diff --git a/program-libs/hasher/Cargo.toml b/program-libs/hasher/Cargo.toml index 5bee32339c..a3e7dc5ba9 100644 --- a/program-libs/hasher/Cargo.toml +++ b/program-libs/hasher/Cargo.toml @@ -2,6 +2,7 @@ name = "light-hasher" version = "5.0.0" description = "Trait for generic usage of hash functions on Solana" +readme = "README.md" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" edition = "2021" diff --git a/program-libs/hasher/README.md b/program-libs/hasher/README.md new file mode 100644 index 0000000000..350841112f --- /dev/null +++ b/program-libs/hasher/README.md @@ -0,0 +1,19 @@ + + +# light-hasher + +Trait for generic hash function usage on Solana. + +| Type | Description | +|------|-------------| +| [`Hasher`] | Trait with `hash`, `hashv`, and `zero_bytes` | +| [`Poseidon`] | Poseidon hash over BN254 | +| [`Keccak`] | Keccak-256 hash | +| [`Sha256`] | SHA-256 hash | +| [`DataHasher`] | Trait to hash structured data | +| [`HasherError`] | Error type for hash operations | +| [`hash_chain`] | Sequential hash chaining | +| [`hash_to_field_size`] | Truncate hash output to BN254 field size | +| [`zero_bytes`] | Precomputed zero-leaf hashes per hasher | + + diff --git a/program-libs/hasher/src/lib.rs b/program-libs/hasher/src/lib.rs index a9aadc19dd..5389e9b8a3 100644 --- a/program-libs/hasher/src/lib.rs +++ b/program-libs/hasher/src/lib.rs @@ -1,3 +1,19 @@ +//! # light-hasher +//! +//! Trait for generic hash function usage on Solana. +//! +//! | Type | Description | +//! |------|-------------| +//! | [`Hasher`] | Trait with `hash`, `hashv`, and `zero_bytes` | +//! | [`Poseidon`] | Poseidon hash over BN254 | +//! | [`Keccak`] | Keccak-256 hash | +//! | [`Sha256`] | SHA-256 hash | +//! | [`DataHasher`] | Trait to hash structured data | +//! | [`HasherError`] | Error type for hash operations | +//! | [`hash_chain`] | Sequential hash chaining | +//! | [`hash_to_field_size`] | Truncate hash output to BN254 field size | +//! | [`zero_bytes`] | Precomputed zero-leaf hashes per hasher | + #![allow(unexpected_cfgs)] #![cfg_attr(not(feature = "std"), no_std)] diff --git a/program-libs/heap/.cargo-rdme.toml b/program-libs/heap/.cargo-rdme.toml new file mode 100644 index 0000000000..09bd28a2b3 --- /dev/null +++ b/program-libs/heap/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-heap" +heading-base-level = 0 diff --git a/program-libs/heap/Cargo.toml b/program-libs/heap/Cargo.toml index e55612d144..c575b8a419 100644 --- a/program-libs/heap/Cargo.toml +++ b/program-libs/heap/Cargo.toml @@ -2,6 +2,7 @@ name = "light-heap" version = "2.0.0" description = "Custom heap allocator used in Light Protocol" +readme = "README.md" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" edition = "2021" diff --git a/program-libs/heap/README.md b/program-libs/heap/README.md new file mode 100644 index 0000000000..c4adc28b8d --- /dev/null +++ b/program-libs/heap/README.md @@ -0,0 +1,14 @@ + + +# light-heap + +Custom bump allocator for Solana programs. Replaces the default +global allocator to allow explicit cursor control and heap freeing. + +| Type | Description | +|------|-------------| +| [`BumpAllocator`] | Global bump allocator with `alloc` and `dealloc` | +| [`HeapError`] | Invalid heap position error | +| [`bench`] | Heap usage benchmarking utilities | + + diff --git a/program-libs/heap/src/lib.rs b/program-libs/heap/src/lib.rs index c3bf26fde0..29d1c87d57 100644 --- a/program-libs/heap/src/lib.rs +++ b/program-libs/heap/src/lib.rs @@ -1,3 +1,14 @@ +//! # light-heap +//! +//! Custom bump allocator for Solana programs. Replaces the default +//! global allocator to allow explicit cursor control and heap freeing. +//! +//! | Type | Description | +//! |------|-------------| +//! | [`BumpAllocator`] | Global bump allocator with `alloc` and `dealloc` | +//! | [`HeapError`] | Invalid heap position error | +//! | [`bench`] | Heap usage benchmarking utilities | + use std::{alloc::Layout, mem::size_of, ptr::null_mut}; pub mod bench; diff --git a/program-libs/indexed-array/.cargo-rdme.toml b/program-libs/indexed-array/.cargo-rdme.toml new file mode 100644 index 0000000000..1fb52a5223 --- /dev/null +++ b/program-libs/indexed-array/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-indexed-array" +heading-base-level = 0 diff --git a/program-libs/indexed-array/Cargo.toml b/program-libs/indexed-array/Cargo.toml index 092bd193e5..df649a7252 100644 --- a/program-libs/indexed-array/Cargo.toml +++ b/program-libs/indexed-array/Cargo.toml @@ -2,6 +2,7 @@ name = "light-indexed-array" version = "0.3.0" description = "Implementation of indexed (and concurrent) Merkle tree in Rust" +readme = "README.md" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" edition = "2021" diff --git a/program-libs/indexed-array/README.md b/program-libs/indexed-array/README.md new file mode 100644 index 0000000000..bfb3c92aae --- /dev/null +++ b/program-libs/indexed-array/README.md @@ -0,0 +1,15 @@ + + +# light-indexed-array + +Indexed array for indexed Merkle trees. Stores elements as +a sorted linked list with index, value, and next-index pointers. + +| Type | Description | +|------|-------------| +| [`array::IndexedElement`] | Element with index, BigUint value, and next-index | +| [`array::IndexedArray`] | Array of indexed elements with insert and lookup | +| [`changelog`] | Raw indexed element and changelog entry types | +| [`errors`] | `IndexedArrayError` variants | + + diff --git a/program-libs/indexed-array/src/lib.rs b/program-libs/indexed-array/src/lib.rs index 97d9cea9c8..b55ccdffe9 100644 --- a/program-libs/indexed-array/src/lib.rs +++ b/program-libs/indexed-array/src/lib.rs @@ -1,3 +1,15 @@ +//! # light-indexed-array +//! +//! Indexed array for indexed Merkle trees. Stores elements as +//! a sorted linked list with index, value, and next-index pointers. +//! +//! | Type | Description | +//! |------|-------------| +//! | [`array::IndexedElement`] | Element with index, BigUint value, and next-index | +//! | [`array::IndexedArray`] | Array of indexed elements with insert and lookup | +//! | [`changelog`] | Raw indexed element and changelog entry types | +//! | [`errors`] | `IndexedArrayError` variants | + pub mod array; pub mod changelog; pub mod errors; diff --git a/program-libs/indexed-merkle-tree/.cargo-rdme.toml b/program-libs/indexed-merkle-tree/.cargo-rdme.toml new file mode 100644 index 0000000000..b2bf65ce8d --- /dev/null +++ b/program-libs/indexed-merkle-tree/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-indexed-merkle-tree" +heading-base-level = 0 diff --git a/program-libs/indexed-merkle-tree/Cargo.toml b/program-libs/indexed-merkle-tree/Cargo.toml index 2332a18cc3..e6ffc4802e 100644 --- a/program-libs/indexed-merkle-tree/Cargo.toml +++ b/program-libs/indexed-merkle-tree/Cargo.toml @@ -2,6 +2,7 @@ name = "light-indexed-merkle-tree" version = "5.0.0" description = "Implementation of indexed (and concurrent) Merkle tree in Rust" +readme = "README.md" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" edition = "2021" diff --git a/program-libs/indexed-merkle-tree/README.md b/program-libs/indexed-merkle-tree/README.md new file mode 100644 index 0000000000..d7b8d66111 --- /dev/null +++ b/program-libs/indexed-merkle-tree/README.md @@ -0,0 +1,18 @@ + + +# light-indexed-merkle-tree + +Indexed concurrent Merkle tree. Extends `ConcurrentMerkleTree` +with a sorted linked-list index for non-inclusion proofs. + +| Type | Description | +|------|-------------| +| [`IndexedMerkleTree`] | Tree with indexed changelog for ordered inserts | +| [`IndexedMerkleTree26`] | Type alias for height-26 indexed trees | +| [`array`] | Indexed array backing the tree elements | +| [`changelog`] | Indexed changelog entries for concurrent patching | +| [`reference`] | Reference implementation for testing | +| [`zero_copy`] | Zero-copy deserialization from account data | +| [`errors`] | `IndexedMerkleTreeError` variants | + + diff --git a/program-libs/indexed-merkle-tree/src/lib.rs b/program-libs/indexed-merkle-tree/src/lib.rs index c28c3523b7..f02e8bd508 100644 --- a/program-libs/indexed-merkle-tree/src/lib.rs +++ b/program-libs/indexed-merkle-tree/src/lib.rs @@ -1,3 +1,18 @@ +//! # light-indexed-merkle-tree +//! +//! Indexed concurrent Merkle tree. Extends `ConcurrentMerkleTree` +//! with a sorted linked-list index for non-inclusion proofs. +//! +//! | Type | Description | +//! |------|-------------| +//! | [`IndexedMerkleTree`] | Tree with indexed changelog for ordered inserts | +//! | [`IndexedMerkleTree26`] | Type alias for height-26 indexed trees | +//! | [`array`] | Indexed array backing the tree elements | +//! | [`changelog`] | Indexed changelog entries for concurrent patching | +//! | [`reference`] | Reference implementation for testing | +//! | [`zero_copy`] | Zero-copy deserialization from account data | +//! | [`errors`] | `IndexedMerkleTreeError` variants | + use std::{ fmt, marker::PhantomData, diff --git a/program-libs/macros/.cargo-rdme.toml b/program-libs/macros/.cargo-rdme.toml new file mode 100644 index 0000000000..df068a823f --- /dev/null +++ b/program-libs/macros/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-macros" +heading-base-level = 0 diff --git a/program-libs/macros/README.md b/program-libs/macros/README.md index 66b4b05676..32b6cc94aa 100644 --- a/program-libs/macros/README.md +++ b/program-libs/macros/README.md @@ -1,2 +1,16 @@ + + # light-macros -Set of proc-macros used in Light Protocol + +Proc macros for Light Protocol on-chain programs. + +| Macro | Description | +|-------|-------------| +| [`pubkey!`](macro@pubkey) | Convert base58 public key to `Pubkey` at compile time | +| [`pubkey_array!`](macro@pubkey_array) | Convert base58 public key to `[u8; 32]` at compile time | +| [`derive_light_cpi_signer!`](macro@derive_light_cpi_signer) | Derive CPI signer PDA, program ID, and bump seed | +| [`derive_light_cpi_signer_pda!`](macro@derive_light_cpi_signer_pda) | Derive CPI signer PDA address and bump seed | +| [`#[heap_neutral]`](macro@heap_neutral) | Assert a function frees all heap it allocates | +| [`#[derive(Noop)]`](derive@Noop) | No-op derive placeholder | + + diff --git a/program-libs/macros/src/lib.rs b/program-libs/macros/src/lib.rs index 8cddf9dc9b..d9ded1d86c 100644 --- a/program-libs/macros/src/lib.rs +++ b/program-libs/macros/src/lib.rs @@ -1,3 +1,16 @@ +//! # light-macros +//! +//! Proc macros for Light Protocol on-chain programs. +//! +//! | Macro | Description | +//! |-------|-------------| +//! | [`pubkey!`](macro@pubkey) | Convert base58 public key to `Pubkey` at compile time | +//! | [`pubkey_array!`](macro@pubkey_array) | Convert base58 public key to `[u8; 32]` at compile time | +//! | [`derive_light_cpi_signer!`](macro@derive_light_cpi_signer) | Derive CPI signer PDA, program ID, and bump seed | +//! | [`derive_light_cpi_signer_pda!`](macro@derive_light_cpi_signer_pda) | Derive CPI signer PDA address and bump seed | +//! | [`#[heap_neutral]`](macro@heap_neutral) | Assert a function frees all heap it allocates | +//! | [`#[derive(Noop)]`](derive@Noop) | No-op derive placeholder | + extern crate proc_macro; use proc_macro::TokenStream; diff --git a/program-libs/merkle-tree-metadata/.cargo-rdme.toml b/program-libs/merkle-tree-metadata/.cargo-rdme.toml new file mode 100644 index 0000000000..66ec8a260a --- /dev/null +++ b/program-libs/merkle-tree-metadata/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-merkle-tree-metadata" +heading-base-level = 0 diff --git a/program-libs/merkle-tree-metadata/Cargo.toml b/program-libs/merkle-tree-metadata/Cargo.toml index 7d89108742..03208ff2c0 100644 --- a/program-libs/merkle-tree-metadata/Cargo.toml +++ b/program-libs/merkle-tree-metadata/Cargo.toml @@ -2,6 +2,7 @@ name = "light-merkle-tree-metadata" version = "0.9.0" description = "Merkle tree metadata for light-concurrent-merkle-tree, light-indexed-merkle-tree, light-batched-merkle-tree." +readme = "README.md" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" edition = "2021" diff --git a/program-libs/merkle-tree-metadata/README.md b/program-libs/merkle-tree-metadata/README.md new file mode 100644 index 0000000000..bd0041530d --- /dev/null +++ b/program-libs/merkle-tree-metadata/README.md @@ -0,0 +1,17 @@ + + +# light-merkle-tree-metadata + +Metadata structs for concurrent, indexed, and batched Merkle trees. + +| Module | Description | +|--------|-------------| +| [`merkle_tree`] | Tree metadata: height, next index, owner, delegate | +| [`queue`] | Queue metadata: type, capacity, sequence numbers | +| [`access`] | Owner and delegate access control checks | +| [`fee`] | Fee parameters for tree and queue operations | +| [`rollover`] | Rollover threshold and status tracking | +| [`events`] | Changelog events emitted on tree updates | +| [`errors`] | `MerkleTreeMetadataError` variants | + + diff --git a/program-libs/merkle-tree-metadata/src/lib.rs b/program-libs/merkle-tree-metadata/src/lib.rs index d963637305..178c3fb194 100644 --- a/program-libs/merkle-tree-metadata/src/lib.rs +++ b/program-libs/merkle-tree-metadata/src/lib.rs @@ -1,3 +1,17 @@ +//! # light-merkle-tree-metadata +//! +//! Metadata structs for concurrent, indexed, and batched Merkle trees. +//! +//! | Module | Description | +//! |--------|-------------| +//! | [`merkle_tree`] | Tree metadata: height, next index, owner, delegate | +//! | [`queue`] | Queue metadata: type, capacity, sequence numbers | +//! | [`access`] | Owner and delegate access control checks | +//! | [`fee`] | Fee parameters for tree and queue operations | +//! | [`rollover`] | Rollover threshold and status tracking | +//! | [`events`] | Changelog events emitted on tree updates | +//! | [`errors`] | `MerkleTreeMetadataError` variants | + pub mod access; pub mod errors; pub mod events; diff --git a/program-libs/token-interface/.cargo-rdme.toml b/program-libs/token-interface/.cargo-rdme.toml new file mode 100644 index 0000000000..85b8f6a3f4 --- /dev/null +++ b/program-libs/token-interface/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-token-interface" +heading-base-level = 0 diff --git a/program-libs/token-interface/Cargo.toml b/program-libs/token-interface/Cargo.toml index aac27dd90f..42c823d0a8 100644 --- a/program-libs/token-interface/Cargo.toml +++ b/program-libs/token-interface/Cargo.toml @@ -3,6 +3,7 @@ name = "light-token-interface" version = "0.3.0" edition = { workspace = true } description = "Light Protocol token instruction data types." +readme = "README.md" license = "MIT" [features] diff --git a/program-libs/token-interface/README.md b/program-libs/token-interface/README.md new file mode 100644 index 0000000000..7b369e1bd8 --- /dev/null +++ b/program-libs/token-interface/README.md @@ -0,0 +1,17 @@ + + +# light-token-interface + +Instruction data types for the light-token program. + +| Module | Description | +|--------|-------------| +| [`instructions`] | Instruction structs for mint, transfer, wrap, unwrap | +| [`state`] | Token account and mint state structs | +| [`discriminator`] | Instruction discriminator constants | +| [`hash_cache`] | Precomputed hashes for token account fields | +| [`pool_derivation`] | SPL/T22 pool account PDA derivation | +| [`token_2022_extensions`] | Token-2022 extension data types | +| [`error`] | `TokenInterfaceError` variants | + + diff --git a/program-libs/token-interface/src/lib.rs b/program-libs/token-interface/src/lib.rs index 92f65d29bc..0074addd38 100644 --- a/program-libs/token-interface/src/lib.rs +++ b/program-libs/token-interface/src/lib.rs @@ -1,3 +1,17 @@ +//! # light-token-interface +//! +//! Instruction data types for the light-token program. +//! +//! | Module | Description | +//! |--------|-------------| +//! | [`instructions`] | Instruction structs for mint, transfer, wrap, unwrap | +//! | [`state`] | Token account and mint state structs | +//! | [`discriminator`] | Instruction discriminator constants | +//! | [`hash_cache`] | Precomputed hashes for token account fields | +//! | [`pool_derivation`] | SPL/T22 pool account PDA derivation | +//! | [`token_2022_extensions`] | Token-2022 extension data types | +//! | [`error`] | `TokenInterfaceError` variants | + pub mod discriminator; pub mod instructions; diff --git a/program-libs/verifier/.cargo-rdme.toml b/program-libs/verifier/.cargo-rdme.toml new file mode 100644 index 0000000000..ef9728398e --- /dev/null +++ b/program-libs/verifier/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-verifier" +heading-base-level = 0 diff --git a/program-libs/verifier/Cargo.toml b/program-libs/verifier/Cargo.toml index 3abe5db16f..8674755af6 100644 --- a/program-libs/verifier/Cargo.toml +++ b/program-libs/verifier/Cargo.toml @@ -2,6 +2,7 @@ name = "light-verifier" version = "8.0.0" description = "ZKP proof verifier used in Light Protocol" +readme = "README.md" repository = "https://github.com/Lightprotocol/light-protocol" license = "Apache-2.0" edition = "2021" diff --git a/program-libs/verifier/README.md b/program-libs/verifier/README.md new file mode 100644 index 0000000000..6dd7993bad --- /dev/null +++ b/program-libs/verifier/README.md @@ -0,0 +1,19 @@ + + +# light-verifier + +ZK proof verifier for Light Protocol. Verifies Groth16 proofs +for inclusion, non-inclusion, and combined address+state operations. + +| Function | Description | +|----------|-------------| +| [`verify_inclusion_proof`] | Verify inclusion for 1–8+ leaves | +| [`verify_create_addresses_proof`] | Verify non-inclusion for 1–8 addresses | +| [`verify_create_addresses_and_inclusion_proof`] | Verify combined address and state proof | +| [`verify_batch_append_with_proofs`] | Verify batch append (10 or 500 leaves) | +| [`verify_batch_update`] | Verify batch state update (10 or 500) | +| [`verify_batch_address_update`] | Verify batch address update (10 or 250) | +| [`select_verifying_key`] | Route to correct verifying key by leaf/address count | +| [`verify`] | Generic Groth16 proof verification | + + diff --git a/program-libs/verifier/src/lib.rs b/program-libs/verifier/src/lib.rs index ea369e67f6..fa6f0a0854 100644 --- a/program-libs/verifier/src/lib.rs +++ b/program-libs/verifier/src/lib.rs @@ -1,3 +1,19 @@ +//! # light-verifier +//! +//! ZK proof verifier for Light Protocol. Verifies Groth16 proofs +//! for inclusion, non-inclusion, and combined address+state operations. +//! +//! | Function | Description | +//! |----------|-------------| +//! | [`verify_inclusion_proof`] | Verify inclusion for 1–8+ leaves | +//! | [`verify_create_addresses_proof`] | Verify non-inclusion for 1–8 addresses | +//! | [`verify_create_addresses_and_inclusion_proof`] | Verify combined address and state proof | +//! | [`verify_batch_append_with_proofs`] | Verify batch append (10 or 500 leaves) | +//! | [`verify_batch_update`] | Verify batch state update (10 or 500) | +//! | [`verify_batch_address_update`] | Verify batch address update (10 or 250) | +//! | [`select_verifying_key`] | Route to correct verifying key by leaf/address count | +//! | [`verify`] | Generic Groth16 proof verification | + use groth16_solana::{ decompression::{decompress_g1, decompress_g2}, groth16::{Groth16Verifier, Groth16Verifyingkey}, diff --git a/scripts/lint.sh b/scripts/lint.sh index a12aaf558e..de90b53179 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -117,3 +117,14 @@ for crate in "${NO_DEFAULT_CRATES[@]}"; do echo "Checking $crate with --no-default-features..." cargo test -p "$crate" --no-run done + +# Check that READMEs are up-to-date with cargo-rdme +echo "Checking READMEs are up-to-date..." +if ! command -v cargo-rdme &> /dev/null; then + cargo install cargo-rdme +fi +for toml in $(find program-libs sdk-libs -name '.cargo-rdme.toml' -type f); do + crate_dir=$(dirname "$toml") + echo "Checking README in $crate_dir..." + (cd "$crate_dir" && cargo rdme --check --no-fail-on-warnings) +done diff --git a/sdk-libs/client/.cargo-rdme.toml b/sdk-libs/client/.cargo-rdme.toml new file mode 100644 index 0000000000..fb5db88c2a --- /dev/null +++ b/sdk-libs/client/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-client" +heading-base-level = 0 diff --git a/sdk-libs/client/README.md b/sdk-libs/client/README.md new file mode 100644 index 0000000000..dca731877c --- /dev/null +++ b/sdk-libs/client/README.md @@ -0,0 +1,88 @@ + + +# Light Client + +A client library for interacting with Light Protocol compressed accounts and RPC endpoints. + +For detailed documentation, visit [zkcompression.com](https://www.zkcompression.com/). +For full program examples, see the [Program Examples](https://github.com/Lightprotocol/program-examples). +For pinocchio solana program development see [`light-sdk-pinocchio`](https://docs.rs/light-sdk-pinocchio). +For rust client developement see [`light-client`](https://docs.rs/light-client). +For rust program testing see [`light-program-test`](https://docs.rs/light-program-test). +For local test validator with light system programs see [Light CLI](https://www.npmjs.com/package/@lightprotocol/zk-compression-cli). + +## Features +- Connect to various RPC endpoints (local test validator, devnet/mainnet) +- Query compressed accounts and validity proofs from RPC endpoints +- Support for both v1 and v2 merkle trees (with v2 feature) +- Start local test validator with Light Protocol programs + +## Prerequisites + +For local test validator usage, install the Light CLI: +```bash +npm i -g @lightprotocol/zk-compression-cli +``` + +## Example + +```rust +use light_client::{ + rpc::{LightClient, LightClientConfig, Rpc}, + indexer::{Indexer, IndexerRpcConfig, RetryConfig}, + local_test_validator::{spawn_validator, LightValidatorConfig}, +}; +use solana_pubkey::Pubkey; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // Start local test validator with Light Protocol programs + let config = LightValidatorConfig { + enable_indexer: true, + enable_prover: true, + wait_time: 75, + sbf_programs: vec![], + upgradeable_programs: vec![], + limit_ledger_size: None, + }; + spawn_validator(config).await; + + // Connect to the validator + let mut rpc = LightClient::new(LightClientConfig::local()).await?; + + // Or connect to devnet/mainnet: + // let mut rpc = LightClient::new(LightClientConfig::new("https://devnet.helius-rpc.com/?api-key=YOUR_KEY")).await?; + // let mut rpc = LightClient::new(LightClientConfig::new("https://mainnet.helius-rpc.com/?api-key=YOUR_KEY")).await?; + + let owner = Pubkey::new_unique(); + + // Create indexer config for queries + let slot = rpc.get_slot().await?; + let config = IndexerRpcConfig { + slot, + retry_config: RetryConfig::default(), + }; + + // Query compressed accounts using Indexer trait + let accounts = rpc + .get_compressed_accounts_by_owner(&owner, None, Some(config)) + .await?; + + println!("Found {} compressed accounts", accounts.value.items.len()); + + // Get validity proofs for creating transactions + let rpc_result = rpc + .get_validity_proof( + vec![], // add account hashes here + vec![], // add addresses with address tree here + None + ) + .await?; + + println!("Got validity proof and proof inputs {:?}", rpc_result.value); + + Ok(()) +} +``` + + diff --git a/sdk-libs/compressed-token-sdk/.cargo-rdme.toml b/sdk-libs/compressed-token-sdk/.cargo-rdme.toml new file mode 100644 index 0000000000..afadd832ab --- /dev/null +++ b/sdk-libs/compressed-token-sdk/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-compressed-token-sdk" +heading-base-level = 0 diff --git a/sdk-libs/compressed-token-sdk/README.md b/sdk-libs/compressed-token-sdk/README.md new file mode 100644 index 0000000000..e50778ca5c --- /dev/null +++ b/sdk-libs/compressed-token-sdk/README.md @@ -0,0 +1,59 @@ + + +# Light Compressed Token SDK + +Low-level SDK for compressed token operations on Light Protocol. + +This crate provides the core building blocks for working with compressed token accounts, +including instruction builders for transfers, mints, and compress/decompress operations. + +## Compressed Token Accounts +- are on Solana mainnet. +- are compressed accounts. +- can hold Light Mint and SPL Mint tokens. +- cost 5,000 lamports to create. +- are well suited for airdrops and reward distribution. + +## Difference to Light-Token: +light-token: Solana account that holds token balances of light-mints, SPL or Token 22 mints. +Compressed token: Compressed account storing token data. Rent-free, for storage and distribution. + +## Features + +- `v1` - Enable v1 compressed token support +- `anchor` - Enable Anchor framework integration +- `anchor-discriminator` - Use Anchor-style discriminators (default) + +For full examples, see the [Compressed Token Examples](https://github.com/Lightprotocol/examples-zk-compression). + +## Operations reference + +| Operation | Docs guide | GitHub example | +|-----------|-----------|----------------| +| Create mint | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/create-mint.ts) | +| Mint to | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/mint-to.ts) | +| Transfer | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/transfer.ts) | +| Approve | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/approve.ts) | +| Revoke | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/revoke.ts) | +| Compress | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/compress.ts) | +| Compress SPL account | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/compress-spl-account.ts) | +| Decompress | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/decompress.ts) | +| Merge token accounts | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/merge-token-accounts.ts) | +| Create token pool | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/create-token-pool.ts) | + +### Toolkit guides + +| Topic | Docs guide | GitHub example | +|-------|-----------|----------------| +| Airdrop | [airdrop](https://www.zkcompression.com/compressed-tokens/advanced-guides/airdrop) | [example](https://github.com/Lightprotocol/examples-zk-compression/tree/main/example-token-distribution) | +| Privy integration | [privy](https://www.zkcompression.com/compressed-tokens/for-privy) | [example](https://github.com/Lightprotocol/examples-zk-compression/tree/main/privy) | + +## Modules + +- [`compressed_token`] - Core compressed token types and instruction builders +- [`error`] - Error types for compressed token operations +- [`utils`] - Utility functions and default account configurations +- [`constants`] - Program IDs and other constants +- [`spl_interface`] - SPL interface PDA derivation utilities + + diff --git a/sdk-libs/compressed-token-sdk/src/lib.rs b/sdk-libs/compressed-token-sdk/src/lib.rs index 8cbcd0b623..761ca3f569 100644 --- a/sdk-libs/compressed-token-sdk/src/lib.rs +++ b/sdk-libs/compressed-token-sdk/src/lib.rs @@ -5,12 +5,48 @@ //! This crate provides the core building blocks for working with compressed token accounts, //! including instruction builders for transfers, mints, and compress/decompress operations. //! +//! ## Compressed Token Accounts +//| - do not require a rent-exempt balance. +//! - are on Solana mainnet. +//! - are compressed accounts. +//! - can hold Light Mint and SPL Mint tokens. +//! - cost 5,000 lamports to create. +//! - are well suited for airdrops and reward distribution. +//! +//! ## Difference to Light-Token: +//! light-token: Solana account that holds token balances of light-mints, SPL or Token 22 mints. +//! Compressed token: Compressed account storing token data. Rent-free, for storage and distribution. +//! //! ## Features //! //! - `v1` - Enable v1 compressed token support //! - `anchor` - Enable Anchor framework integration //! - `anchor-discriminator` - Use Anchor-style discriminators (default) //! +//! For full examples, see the [Compressed Token Examples](https://github.com/Lightprotocol/examples-zk-compression). +//! +//! ## Operations reference +//! +//! | Operation | Docs guide | GitHub example | +//! |-----------|-----------|----------------| +//! | Create mint | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/create-mint.ts) | +//! | Mint to | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/mint-to.ts) | +//! | Transfer | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/transfer.ts) | +//! | Approve | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/approve.ts) | +//! | Revoke | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/revoke.ts) | +//! | Compress | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/compress.ts) | +//! | Compress SPL account | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/compress-spl-account.ts) | +//! | Decompress | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/decompress.ts) | +//! | Merge token accounts | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/merge-token-accounts.ts) | +//! | Create token pool | [create-compressed-token-accounts](https://www.zkcompression.com/compressed-tokens/guides/create-compressed-token-accounts) | [example](https://github.com/Lightprotocol/examples-zk-compression/blob/main/compressed-token-cookbook/actions/create-token-pool.ts) | +//! +//! ### Toolkit guides +//! +//! | Topic | Docs guide | GitHub example | +//! |-------|-----------|----------------| +//! | Airdrop | [airdrop](https://www.zkcompression.com/compressed-tokens/advanced-guides/airdrop) | [example](https://github.com/Lightprotocol/examples-zk-compression/tree/main/example-token-distribution) | +//! | Privy integration | [privy](https://www.zkcompression.com/compressed-tokens/for-privy) | [example](https://github.com/Lightprotocol/examples-zk-compression/tree/main/privy) | +//! //! ## Modules //! //! - [`compressed_token`] - Core compressed token types and instruction builders diff --git a/sdk-libs/event/.cargo-rdme.toml b/sdk-libs/event/.cargo-rdme.toml new file mode 100644 index 0000000000..c00ab92c23 --- /dev/null +++ b/sdk-libs/event/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-event" +heading-base-level = 0 diff --git a/sdk-libs/event/README.md b/sdk-libs/event/README.md new file mode 100644 index 0000000000..e515979514 --- /dev/null +++ b/sdk-libs/event/README.md @@ -0,0 +1,13 @@ + + +# light-event + +Event types and parsing for Light Protocol transactions. + +| Type | Description | +|------|-------------| +| [`PublicTransactionEvent`](event::PublicTransactionEvent) | Transaction event with input/output compressed account hashes | +| [`BatchPublicTransactionEvent`](event::BatchPublicTransactionEvent) | Batched event with accounts, addresses, and sequence numbers | +| [`event_from_light_transaction`](parse::event_from_light_transaction) | Parse transaction instructions into a batch event | + + diff --git a/sdk-libs/event/src/lib.rs b/sdk-libs/event/src/lib.rs index 5c137546a1..6a78baffe8 100644 --- a/sdk-libs/event/src/lib.rs +++ b/sdk-libs/event/src/lib.rs @@ -1,4 +1,12 @@ -// Light Protocol event types and utilities +//! # light-event +//! +//! Event types and parsing for Light Protocol transactions. +//! +//! | Type | Description | +//! |------|-------------| +//! | [`PublicTransactionEvent`](event::PublicTransactionEvent) | Transaction event with input/output compressed account hashes | +//! | [`BatchPublicTransactionEvent`](event::BatchPublicTransactionEvent) | Batched event with accounts, addresses, and sequence numbers | +//! | [`event_from_light_transaction`](parse::event_from_light_transaction) | Parse transaction instructions into a batch event | pub mod error; pub mod event; diff --git a/sdk-libs/instruction-decoder-derive/.cargo-rdme.toml b/sdk-libs/instruction-decoder-derive/.cargo-rdme.toml new file mode 100644 index 0000000000..c42bdc3483 --- /dev/null +++ b/sdk-libs/instruction-decoder-derive/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-instruction-decoder-derive" +heading-base-level = 0 diff --git a/sdk-libs/instruction-decoder-derive/README.md b/sdk-libs/instruction-decoder-derive/README.md new file mode 100644 index 0000000000..bc1b72817f --- /dev/null +++ b/sdk-libs/instruction-decoder-derive/README.md @@ -0,0 +1,38 @@ + + +Derive macros for InstructionDecoder implementations + +This crate provides two macros: +1. `#[derive(InstructionDecoder)]` - For instruction enums (native programs) +2. `#[instruction_decoder]` - Attribute macro for Anchor program modules + +The attribute macro extracts function names from the program module and generates +an instruction enum with `#[derive(InstructionDecoder)]` applied. + +## Enhanced InstructionDecoder for Anchor Programs + +The derive macro supports an enhanced mode that references Anchor-generated types +for account names and parameter decoding: + +```rust +use light_instruction_decoder_derive::InstructionDecoder; + +#[derive(InstructionDecoder)] +#[instruction_decoder( + program_id = "MyProgram111111111111111111111111111111111", + program_name = "My Program" +)] +pub enum MyInstruction { + #[instruction_decoder(accounts = CreateRecord, params = CreateRecordParams)] + CreateRecord, + + #[instruction_decoder(accounts = UpdateRecord)] + UpdateRecord, +} +``` + +This generates a decoder that: +- Gets account names from `>::ACCOUNT_NAMES` +- Decodes instruction data using `ParamsType::try_from_slice()` with Debug output + + diff --git a/sdk-libs/instruction-decoder/.cargo-rdme.toml b/sdk-libs/instruction-decoder/.cargo-rdme.toml new file mode 100644 index 0000000000..ee06db745a --- /dev/null +++ b/sdk-libs/instruction-decoder/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-instruction-decoder" +heading-base-level = 0 diff --git a/sdk-libs/instruction-decoder/README.md b/sdk-libs/instruction-decoder/README.md new file mode 100644 index 0000000000..1363f6db0e --- /dev/null +++ b/sdk-libs/instruction-decoder/README.md @@ -0,0 +1,23 @@ + + +# light-instruction-decoder + +Instruction decoder and transaction logger for Light Protocol programs. + +This crate provides: +- Core types for instruction decoding (`DecodedField`, `DecodedInstruction`, `InstructionDecoder` trait) +- Decoder registry for managing multiple program decoders +- Built-in decoders for Light Protocol programs (System, Compressed Token, etc.) +- Transaction logging configuration and formatting utilities + +| Export | Description | +|--------|-------------| +| [`InstructionDecoder`] | Trait for decoding program instructions | +| [`DecoderRegistry`] | Registry for multiple program decoders | +| [`EnhancedLoggingConfig`] | Transaction logging configuration | +| [`TransactionFormatter`] | Format transaction logs with ANSI colors | +| [`instruction_decoder`] | Derive macro for decoder implementations | + +Note: Most functionality is only available off-chain (not on Solana targets). + + diff --git a/sdk-libs/instruction-decoder/src/lib.rs b/sdk-libs/instruction-decoder/src/lib.rs index 507322cdfc..63b51d9f9f 100644 --- a/sdk-libs/instruction-decoder/src/lib.rs +++ b/sdk-libs/instruction-decoder/src/lib.rs @@ -1,13 +1,20 @@ -//! Instruction decoder library for Light Protocol. +//! # light-instruction-decoder +//! +//! Instruction decoder and transaction logger for Light Protocol programs. //! //! This crate provides: -//! - Core types for instruction decoding (DecodedField, DecodedInstruction, InstructionDecoder trait) +//! - Core types for instruction decoding (`DecodedField`, `DecodedInstruction`, `InstructionDecoder` trait) //! - Decoder registry for managing multiple program decoders //! - Built-in decoders for Light Protocol programs (System, Compressed Token, etc.) //! - Transaction logging configuration and formatting utilities //! -//! The crate is designed to be independent of LiteSVM/test infrastructure, -//! enabling use in both test environments and standalone tools. +//! | Export | Description | +//! |--------|-------------| +//! | [`InstructionDecoder`] | Trait for decoding program instructions | +//! | [`DecoderRegistry`] | Registry for multiple program decoders | +//! | [`EnhancedLoggingConfig`] | Transaction logging configuration | +//! | [`TransactionFormatter`] | Format transaction logs with ANSI colors | +//! | [`instruction_decoder`] | Derive macro for decoder implementations | //! //! Note: Most functionality is only available off-chain (not on Solana targets). diff --git a/sdk-libs/program-test/.cargo-rdme.toml b/sdk-libs/program-test/.cargo-rdme.toml new file mode 100644 index 0000000000..e813350156 --- /dev/null +++ b/sdk-libs/program-test/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-program-test" +heading-base-level = 0 diff --git a/sdk-libs/program-test/README.md b/sdk-libs/program-test/README.md new file mode 100644 index 0000000000..62f36d3ab1 --- /dev/null +++ b/sdk-libs/program-test/README.md @@ -0,0 +1,133 @@ + + +# Light Program Test + +A fast local test environment for Solana programs using compressed accounts and tokens. + +For Rust and Anchor program development, see [`light-sdk`](https://docs.rs/light-sdk). +For Rust client, see [`light-client`](https://docs.rs/light-client). +For full program examples, see the [Program Examples](https://github.com/Lightprotocol/program-examples). +For detailed documentation, visit [zkcompression.com](https://www.zkcompression.com/). + +# Features + +- `v2` - Enables v2 batched Merkle trees. + +## Testing Features +- Fast in-memory indexer and SVM via [LiteSVM](https://github.com/LiteSVM/LiteSVM) +- Supports custom programs +- Prover server via [Light CLI](https://www.npmjs.com/package/@lightprotocol/zk-compression-cli) + +**Use `light-program-test` when:** +- You need fast test execution +- You write unit/integration tests for your program or client code + +**Use `solana-test-validator` when:** +- You need RPC methods or external tools that are incompatible with LiteSVM +- Testing against real validator behavior + +## Configuration Options + +### `with_prover: bool` +- `true`: Starts a prover server in the background for generating validity proofs +- `false`: Runs without prover (faster for tests that don't need proofs, or repeated test runs to reduce startup time) + +### `additional_programs: Option>` +- Specify custom programs to deploy alongside the default Light Protocol programs +- Format: `vec![("program_name", program_id)]` +- Programs are loaded from built artifacts + +## Prerequisites + +1. **ZK Compression CLI**: Required to start the prover server and download Light Protocol programs + ```bash + npm i -g @lightprotocol/zk-compression-cli + ``` + - If programs are missing after CLI installation, run `light test-validator` once to download them + +2. **Build programs**: Run `cargo test-sbf` to build program binaries and set the required + environment variables for locating program artifacts + +## Prover Server + +The prover server runs on port 3001 when enabled. To manually stop it: +```bash +# Find the process ID +lsof -i:3001 +# Kill the process +kill +``` + +## Debugging + +Set `RUST_BACKTRACE=1` to show detailed transaction information including accounts and parsed instructions: +```bash +RUST_BACKTRACE=1 cargo test-sbf -- --nocapture +``` + +## Examples + +### V1 Trees +```rust +use light_program_test::{LightProgramTest, ProgramTestConfig}; +use solana_sdk::signer::{keypair::Keypair, Signer}; + +#[tokio::test] +async fn test_v1_compressed_account() { + // Initialize with v1 trees + let config = ProgramTestConfig::default(); + let mut rpc = LightProgramTest::new(config).await.unwrap(); + + let payer = Keypair::new(); + + // Get v1 tree info + let address_tree_info = rpc.get_address_tree_v1(); + let state_tree_info = rpc.get_random_state_tree_info(); + + // Airdrop for testing + rpc.airdrop_lamports(&payer.pubkey(), 1_000_000_000).await.unwrap(); + + // Query compressed accounts using Indexer trait + let accounts = rpc.indexer().unwrap() + .get_compressed_accounts_by_owner(&payer.pubkey()) + .await + .unwrap(); + + println!("Found {} compressed accounts", accounts.len()); +} +``` + +### V2 Trees +```rust +use light_program_test::{LightProgramTest, ProgramTestConfig}; +use solana_sdk::signer::{keypair::Keypair, Signer}; + +#[tokio::test] +async fn test_v2_compressed_account() { + // Initialize with v2 batched trees and custom program + let config = ProgramTestConfig::new_v2( + true, // with_prover + Some(vec![("my_program", my_program::ID)]) + ); + let mut rpc = LightProgramTest::new(config).await.unwrap(); + + let payer = Keypair::new(); + + // Get v2 tree pubkeys + let address_tree_info = rpc.get_address_tree_v2(); + let state_tree_info = rpc.get_random_state_tree_info(); + + + rpc.airdrop_lamports(&payer.pubkey(), 1_000_000_000).await.unwrap(); + + // Query using Indexer trait methods + let accounts = rpc.indexer().unwrap() + .get_compressed_accounts_by_owner(&payer.pubkey()) + .await + .unwrap(); + + println!("Found {} compressed accounts with v2 trees", accounts.len()); +} +``` + + diff --git a/sdk-libs/program-test/src/lib.rs b/sdk-libs/program-test/src/lib.rs index ddca5f3e5f..0f3a66153c 100644 --- a/sdk-libs/program-test/src/lib.rs +++ b/sdk-libs/program-test/src/lib.rs @@ -69,9 +69,9 @@ //! ## Examples //! //! ### V1 Trees -//! ```rust +//! ```rust,ignore //! use light_program_test::{LightProgramTest, ProgramTestConfig}; -//! use solana_sdk::signer::Signer; +//! use solana_sdk::signer::{keypair::Keypair, Signer}; //! //! #[tokio::test] //! async fn test_v1_compressed_account() { @@ -99,9 +99,9 @@ //! ``` //! //! ### V2 Trees -//! ```rust +//! ```rust,ignore //! use light_program_test::{LightProgramTest, ProgramTestConfig}; -//! use solana_sdk::signer::Signer; +//! use solana_sdk::signer::{keypair::Keypair, Signer}; //! //! #[tokio::test] //! async fn test_v2_compressed_account() { diff --git a/sdk-libs/sdk-pinocchio/.cargo-rdme.toml b/sdk-libs/sdk-pinocchio/.cargo-rdme.toml new file mode 100644 index 0000000000..f84e79c450 --- /dev/null +++ b/sdk-libs/sdk-pinocchio/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-sdk-pinocchio" +heading-base-level = 0 diff --git a/sdk-libs/sdk-pinocchio/README.md b/sdk-libs/sdk-pinocchio/README.md new file mode 100644 index 0000000000..7783f59cac --- /dev/null +++ b/sdk-libs/sdk-pinocchio/README.md @@ -0,0 +1,16 @@ + + +# light-sdk-pinocchio + +Light Protocol SDK for native Solana programs using pinocchio. + +| Export | Description | +|--------|-------------| +| [`derive_light_cpi_signer`] | Derive CPI signer and bump at compile time | +| [`LightDiscriminator`] | Discriminator trait; derive macro requires `light-account` feature | +| [`LightAccount`] | Compressed account wrapper (requires `light-account` feature) | +| [`address`] | Address derivation (v1 and v2) | +| [`cpi`] | Light System Program CPI invocation | +| [`instruction`] | Instruction types and helpers | + + diff --git a/sdk-libs/sdk-pinocchio/src/lib.rs b/sdk-libs/sdk-pinocchio/src/lib.rs index 551ccd9064..e38611a6e5 100644 --- a/sdk-libs/sdk-pinocchio/src/lib.rs +++ b/sdk-libs/sdk-pinocchio/src/lib.rs @@ -1,3 +1,16 @@ +//! # light-sdk-pinocchio +//! +//! Light Protocol SDK for native Solana programs using pinocchio. +//! +//! | Export | Description | +//! |--------|-------------| +//! | [`derive_light_cpi_signer`] | Derive CPI signer and bump at compile time | +//! | [`LightDiscriminator`] | Discriminator trait; derive macro requires `light-account` feature | +//! | [`LightAccount`] | Compressed account wrapper (requires `light-account` feature) | +//! | [`address`] | Address derivation (v1 and v2) | +//! | [`cpi`] | Light System Program CPI invocation | +//! | [`instruction`] | Instruction types and helpers | + pub mod address; pub mod cpi; pub mod error; diff --git a/sdk-libs/sdk-types/.cargo-rdme.toml b/sdk-libs/sdk-types/.cargo-rdme.toml new file mode 100644 index 0000000000..f79e1c20b1 --- /dev/null +++ b/sdk-libs/sdk-types/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-sdk-types" +heading-base-level = 0 diff --git a/sdk-libs/sdk-types/README.md b/sdk-libs/sdk-types/README.md new file mode 100644 index 0000000000..5d786f68ee --- /dev/null +++ b/sdk-libs/sdk-types/README.md @@ -0,0 +1,15 @@ + + +# light-sdk-types + +Core types for the Light Protocol SDK. + +| Type | Description | +|------|-------------| +| [`RentSponsor`] | PDA to sponsor rent-exemption of Solana accounts using the Light Token Program | +| [`CpiAccounts`](cpi_accounts::CpiAccounts) | Container for CPI system and tree accounts | +| [`CpiSigner`] | Program ID, signer, and bump for CPI invocation | +| [`address`] | Address derivation functions (v1 and v2) | +| [`constants`] | Protocol program IDs and discriminators | + + diff --git a/sdk-libs/sdk-types/src/lib.rs b/sdk-libs/sdk-types/src/lib.rs index b63eebc639..e48ca9941b 100644 --- a/sdk-libs/sdk-types/src/lib.rs +++ b/sdk-libs/sdk-types/src/lib.rs @@ -1,3 +1,15 @@ +//! # light-sdk-types +//! +//! Core types for the Light Protocol SDK. +//! +//! | Type | Description | +//! |------|-------------| +//! | [`RentSponsor`] | PDA to sponsor rent-exemption of Solana accounts using the Light Token Program | +//! | [`CpiAccounts`](cpi_accounts::CpiAccounts) | Container for CPI system and tree accounts | +//! | [`CpiSigner`] | Program ID, signer, and bump for CPI invocation | +//! | [`address`] | Address derivation functions (v1 and v2) | +//! | [`constants`] | Protocol program IDs and discriminators | + #![cfg_attr(not(feature = "std"), no_std)] #[cfg(all(not(feature = "std"), feature = "alloc"))] diff --git a/sdk-libs/sdk/.cargo-rdme.toml b/sdk-libs/sdk/.cargo-rdme.toml new file mode 100644 index 0000000000..9048f9d851 --- /dev/null +++ b/sdk-libs/sdk/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-sdk" +heading-base-level = 0 diff --git a/sdk-libs/sdk/README.md b/sdk-libs/sdk/README.md new file mode 100644 index 0000000000..e4f4fc7e45 --- /dev/null +++ b/sdk-libs/sdk/README.md @@ -0,0 +1,151 @@ + + +The base library to use Compressed Accounts in Solana on-chain Rust and Anchor programs. +Compressed accounts do not require rent-exemption, which makes them suitable for: +- user owned accounts +- not for config accounts which are often read +- not pool accounts, since compressed accounts cannot be used concurrently + +Compressed Accounts store state as account hashes in State Merkle trees. +and unique addresses in Address Merkle trees. +Validity proofs (zero-knowledge proofs) verify that compressed account +state exists and new addresses do not exist yet. + +- No rent exemption payment required. +- Constant 128-byte validity proof per transaction for one or multiple compressed accounts and addresses. +- Compressed account data is sent as instruction data when accessed. +- State and address trees are managed by the protocol. + +For full program examples, see the [Program Examples](https://github.com/Lightprotocol/program-examples). +For detailed documentation, visit [zkcompression.com](https://www.zkcompression.com/). +For pinocchio solana program development see [`light-sdk-pinocchio`](https://docs.rs/light-sdk-pinocchio). +For rust client development see [`light-client`](https://docs.rs/light-client). +For rust program testing see [`light-program-test`](https://docs.rs/light-program-test). +For local test validator with light system programs see [Light CLI](https://www.npmjs.com/package/@lightprotocol/zk-compression-cli). + +## Difference to Light-Accounts (Light-PDA) +Light-PDAs are Solana accounts with sponsored rent-exemption. +There is no proof required for interactions with Light-PDAs which makes +them suitable for Defi Usecases. Compressed PDAs don't require rent-exemption, +but a proof for interactions. + +# Using Compressed Accounts in Solana Programs +1. [`Instruction`](https://docs.rs/light-sdk/latest/light_sdk/instruction/) + - `CompressedAccountMeta` - Compressed account metadata structs for instruction data. + - `PackedAccounts` - Abstraction to prepare accounts offchain for instructions with compressed accounts. + - `ValidityProof` - Proves that new addresses don't exist yet, and compressed account state exists. +2. Compressed Account in Program + - [`LightAccount`](https://docs.rs/light-sdk/latest/light_sdk/account/) - Compressed account abstraction similar to anchor Account. + - [`derive_address`](https://docs.rs/light-sdk/latest/light_sdk/address/) - Create a compressed account address. + - [`LightDiscriminator`] - DeriveMacro to derive a compressed account discriminator. +3. [`Cpi`](https://docs.rs/light-sdk/latest/light_sdk/cpi/) + - `CpiAccounts` - Prepare accounts to cpi the light system program. + - `LightSystemProgramCpi` - Prepare instruction data to cpi the light system program. + - [`InvokeLightSystemProgram::invoke`](https://docs.rs/light-sdk/latest/light_sdk/cpi/) - Invoke the light system program via cpi. + +# Client Program Interaction Flow +```text + ├─ 𝐂𝐥𝐢𝐞𝐧𝐭 + │ ├─ Get ValidityProof from RPC. + │ ├─ pack accounts with PackedAccounts into PackedAddressTreeInfo and PackedStateTreeInfo. + │ ├─ pack CompressedAccountMeta. + │ ├─ Build Instruction from PackedAccounts and CompressedAccountMetas. + │ └─ Send transaction. + │ + └─ 𝐂𝐮𝐬𝐭𝐨𝐦 𝐏𝐫𝐨𝐠𝐫𝐚𝐦 + ├─ CpiAccounts parse accounts consistent with PackedAccounts. + ├─ LightAccount instantiates from CompressedAccountMeta. + │ + └─ 𝐋𝐢𝐠𝐡𝐭 𝐒𝐲𝐬𝐭𝐞𝐦 𝐏𝐫𝐨𝐠𝐫𝐚𝐦 𝐂𝐏𝐈 + ├─ Verify ValidityProof. + ├─ Update State Merkle tree. + ├─ Update Address Merkle tree. + └─ Complete atomic state transition. +``` + +# Features +1. `anchor` - Derives AnchorSerialize, AnchorDeserialize instead of BorshSerialize, BorshDeserialize. + +2. `v2` + - available on devnet, localnet, and light-program-test. + - Support for optimized v2 light system program instructions. + +3. `cpi-context` - Enables CPI context operations for batched compressed account operations. + - available on devnet, localnet, and light-program-test. + - Enables the use of one validity proof across multiple cpis from different programs in one instruction. + - For example spending compressed tokens (owned by the ctoken program) and updating a compressed pda (owned by a custom program) + with one validity proof. + - An instruction should not use more than one validity proof. + - Requires the v2 feature. + +### Example Solana program code to create a compressed account +```rust, compile_fail +use anchor_lang::{prelude::*, Discriminator}; +use light_sdk::{ + account::LightAccount, + address::v1::derive_address, + cpi::{v1::LightSystemProgramCpi, CpiAccounts, InvokeLightSystemProgram, LightCpiInstruction}, + derive_light_cpi_signer, + instruction::{account_meta::CompressedAccountMeta, PackedAddressTreeInfo}, + CpiSigner, LightDiscriminator, LightHasher, ValidityProof, +}; + +declare_id!("2tzfijPBGbrR5PboyFUFKzfEoLTwdDSHUjANCw929wyt"); + +pub const LIGHT_CPI_SIGNER: CpiSigner = + derive_light_cpi_signer!("2tzfijPBGbrR5PboyFUFKzfEoLTwdDSHUjANCw929wyt"); + +#[program] +pub mod counter { + + use super::*; + + pub fn create_compressed_account<'info>( + ctx: Context<'_, '_, '_, 'info, CreateCompressedAccount<'info>>, + proof: ValidityProof, + address_tree_info: PackedAddressTreeInfo, + output_tree_index: u8, + ) -> Result<()> { + let light_cpi_accounts = CpiAccounts::new( + ctx.accounts.fee_payer.as_ref(), + ctx.remaining_accounts, + crate::LIGHT_CPI_SIGNER, + )?; + + let (address, address_seed) = derive_address( + &[b"counter", ctx.accounts.fee_payer.key().as_ref()], + &address_tree_info.get_tree_pubkey(&light_cpi_accounts)?, + &crate::ID, + ); + let new_address_params = address_tree_info + .into_new_address_params_packed(address_seed); + + let mut my_compressed_account = LightAccount::::new_init( + &crate::ID, + Some(address), + output_tree_index, + ); + + my_compressed_account.owner = ctx.accounts.fee_payer.key(); + + LightSystemProgramCpi::new_cpi(crate::LIGHT_CPI_SIGNER, proof) + .with_light_account(my_compressed_account)? + .with_new_addresses(&[new_address_params]) + .invoke(light_cpi_accounts) + } +} + +#[derive(Accounts)] +pub struct CreateCompressedAccount<'info> { + #[account(mut)] + pub fee_payer: Signer<'info>, +} + +#[derive(Clone, Debug, Default, LightDiscriminator)] +pub struct CounterAccount { + pub owner: Pubkey, + pub counter: u64 +} +``` + + diff --git a/sdk-libs/sdk/src/lib.rs b/sdk-libs/sdk/src/lib.rs index fce8b42a5d..cca4cd951c 100644 --- a/sdk-libs/sdk/src/lib.rs +++ b/sdk-libs/sdk/src/lib.rs @@ -1,4 +1,8 @@ //! The base library to use Compressed Accounts in Solana on-chain Rust and Anchor programs. +//! Compressed accounts do not require rent-exemption, which makes them suitable for: +//! - user owned accounts +//! - not for config accounts which are often read +//! - not pool accounts, since compressed accounts cannot be used concurrently //! //! Compressed Accounts store state as account hashes in State Merkle trees. //! and unique addresses in Address Merkle trees. @@ -17,6 +21,12 @@ //! For rust program testing see [`light-program-test`](https://docs.rs/light-program-test). //! For local test validator with light system programs see [Light CLI](https://www.npmjs.com/package/@lightprotocol/zk-compression-cli). //! +//! ## Difference to Light-Accounts (Light-PDA) +//! Light-PDAs are Solana accounts with sponsored rent-exemption. +//! There is no proof required for interactions with Light-PDAs which makes +//! them suitable for Defi Usecases. Compressed PDAs don't require rent-exemption, +//! but a proof for interactions. +//! //! # Using Compressed Accounts in Solana Programs //! 1. [`Instruction`](crate::instruction) //! - [`CompressedAccountMeta`](crate::instruction::account_meta::CompressedAccountMeta) - Compressed account metadata structs for instruction data. diff --git a/sdk-libs/token-client/.cargo-rdme.toml b/sdk-libs/token-client/.cargo-rdme.toml new file mode 100644 index 0000000000..8790fca891 --- /dev/null +++ b/sdk-libs/token-client/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-token-client" +heading-base-level = 0 diff --git a/sdk-libs/token-client/README.md b/sdk-libs/token-client/README.md new file mode 100644 index 0000000000..97c71c728e --- /dev/null +++ b/sdk-libs/token-client/README.md @@ -0,0 +1,22 @@ + + +# light-token-client + +Rust client for light-token. Each action builds, signs, +and sends the transaction. + +| Action | Description | +|--------|-------------| +| [`CreateMint`] | Create a light-token mint with metadata | +| [`CreateAta`] | Create an associated light-token account | +| [`MintTo`] | Mint tokens to a light-token account | +| [`Transfer`] | Transfer light-tokens between accounts | +| [`TransferChecked`] | Transfer with decimal validation | +| [`TransferInterface`] | Transfer between light-token, T22, and SPL accounts | +| [`Approve`] | Approve a delegate | +| [`Revoke`] | Revoke a delegate | +| [`Wrap`] | Wrap SPL/T22 to light-token | +| [`Unwrap`] | Unwrap light-token to SPL/T22 | + + + diff --git a/sdk-libs/token-client/src/lib.rs b/sdk-libs/token-client/src/lib.rs index 4368dfed4a..31314a68ef 100644 --- a/sdk-libs/token-client/src/lib.rs +++ b/sdk-libs/token-client/src/lib.rs @@ -1,3 +1,23 @@ +//! # light-token-client +//! +//! Rust client for light-token. Each action builds, signs, +//! and sends the transaction. +//! +//! | Action | Description | +//! |--------|-------------| +//! | [`CreateMint`] | Create a light-token mint with metadata | +//! | [`CreateAta`] | Create an associated light-token account | +//! | [`MintTo`] | Mint tokens to a light-token account | +//! | [`Transfer`] | Transfer light-tokens between accounts | +//! | [`TransferChecked`] | Transfer with decimal validation | +//! | [`TransferInterface`] | Transfer between light-token, T22, and SPL accounts | +//! | [`Approve`] | Approve a delegate | +//! | [`Revoke`] | Revoke a delegate | +//! | [`Wrap`] | Wrap SPL/T22 to light-token | +//! | [`Unwrap`] | Unwrap light-token to SPL/T22 | +//! +//! + pub mod actions; // Re-export actions at crate root for convenience diff --git a/sdk-libs/token-sdk/.cargo-rdme.toml b/sdk-libs/token-sdk/.cargo-rdme.toml new file mode 100644 index 0000000000..25bfae97d1 --- /dev/null +++ b/sdk-libs/token-sdk/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-token" +heading-base-level = 0 diff --git a/sdk-libs/token-sdk/README.md b/sdk-libs/token-sdk/README.md new file mode 100644 index 0000000000..b558a367a0 --- /dev/null +++ b/sdk-libs/token-sdk/README.md @@ -0,0 +1,75 @@ + + +# Light Token SDK + +The base library to use Light Token Accounts, Light Mints, and compressed token accounts. + +## Light Token Accounts +- are on Solana devnet. +- are Solana accounts. +- are functionally equivalent to SPL token accounts. +- can hold tokens of Light, SPL and Token 2022 mints. +- cost 17,288 lamports to create with 24 hours rent. +- are rentfree: + - rent exemption is sponsored by the token program. + - rent is 388 lamports per rent epoch (1.5 hours). + - once the account's lamports balance is insufficient, it is auto-compressed to a compressed token account. + - the accounts state is cryptographically preserved on the Solana ledger. + - compressed tokens can be decompressed to a Light Token account. + - configurable lamports per write (eg transfer) keep the Light Token account perpetually funded when used. So you don't have to worry about funding rent. + - users load a compressed account into a light account in-flight when using the account again. + +## Light Mints +- are on Solana devnet. +- are Compressed accounts. +- cost 15,000 lamports to create. +- support `TokenMetadata`. +- have the same rent-config as light token accounts + +## Compressed Token Accounts +- are on Solana mainnet. +- are compressed accounts. +- can hold Light Mint and SPL Mint tokens. +- cost 5,000 lamports to create. +- are well suited for airdrops and reward distribution. + +For full program examples, see the [Light Token Examples](https://github.com/Lightprotocol/examples-light-token). + +| Operation | Docs guide | GitHub example | +|-----------|-----------|----------------| +| `CreateAssociatedAccountCpi` | [create-ata](https://zkcompression.com/light-token/cookbook/create-ata) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/create-ata) | +| `CreateTokenAccountCpi` | [create-token-account](https://zkcompression.com/light-token/cookbook/create-token-account) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/create-token-account) | +| `CreateMintCpi` | [create-mint](https://zkcompression.com/light-token/cookbook/create-mint) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/create-mint) | +| `MintToCpi` | [mint-to](https://zkcompression.com/light-token/cookbook/mint-to) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/mint-to) | +| `MintToCheckedCpi` | [mint-to](https://zkcompression.com/light-token/cookbook/mint-to) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/mint-to-checked) | +| `BurnCpi` | [burn](https://zkcompression.com/light-token/cookbook/burn) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/burn) | +| `TransferCheckedCpi` | [transfer-checked](https://zkcompression.com/light-token/cookbook/transfer-checked) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/transfer-checked) | +| `TransferInterfaceCpi` | [transfer-interface](https://zkcompression.com/light-token/cookbook/transfer-interface) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/transfer-interface) | +| `ApproveCpi` | [approve-revoke](https://zkcompression.com/light-token/cookbook/approve-revoke) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/approve) | +| `RevokeCpi` | [approve-revoke](https://zkcompression.com/light-token/cookbook/approve-revoke) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/revoke) | +| `FreezeCpi` | [freeze-thaw](https://zkcompression.com/light-token/cookbook/freeze-thaw) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/freeze) | +| `ThawCpi` | [freeze-thaw](https://zkcompression.com/light-token/cookbook/freeze-thaw) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/thaw) | +| `CloseAccountCpi` | [close-token-account](https://zkcompression.com/light-token/cookbook/close-token-account) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/close-token-account) | + +## Features + +1. anchor - Derives AnchorSerialize, AnchorDeserialize instead of BorshSerialize, BorshDeserialize. +2. compressible - utility functions for compressible sdk macros. + +## Common Operations + +| Operation | Instruction Builder | CPI Builder | +|-----------|----------------|-------------| +| Create Associated Token Account | [`CreateAssociatedTokenAccount`](instruction::CreateAssociatedTokenAccount) | [`CreateAssociatedAccountCpi`](instruction::CreateAssociatedAccountCpi) | +| Create Token Account | [`CreateTokenAccount`](instruction::CreateTokenAccount) | [`CreateTokenAccountCpi`](instruction::CreateTokenAccountCpi) | +| Transfer | [`Transfer`](instruction::Transfer) | [`TransferCpi`](instruction::TransferCpi) | +| Transfer Interface (auto-detect) | [`TransferInterface`](instruction::TransferInterface) | [`TransferInterfaceCpi`](instruction::TransferInterfaceCpi) | +| Close Token account | [`CloseAccount`](instruction::CloseAccount) | [`CloseAccountCpi`](instruction::CloseAccountCpi) | +| Create Mint | [`CreateMint`](instruction::CreateMint) | [`CreateMintCpi`](instruction::CreateMintCpi) | +| MintTo | [`MintTo`](instruction::MintTo) | [`MintToCpi`](instruction::MintToCpi) | + + +# Disclaimer +This library is not audited and in a beta state. Use at your own risk and expect breaking changes. + + diff --git a/sdk-libs/token-sdk/src/lib.rs b/sdk-libs/token-sdk/src/lib.rs index 3360208e0e..7bb6bc7f3a 100644 --- a/sdk-libs/token-sdk/src/lib.rs +++ b/sdk-libs/token-sdk/src/lib.rs @@ -5,36 +5,49 @@ //! ## Light Token Accounts //! - are on Solana devnet. //! - are Solana accounts. -//! - can hold Light Mint and SPL Mint tokens. +//! - are functionally equivalent to SPL token accounts. +//! - can hold tokens of Light, SPL and Token 2022 mints. //! - cost 17,288 lamports to create with 24 hours rent. //! - are rentfree: -//! - rent exemption is sponsored by the protocol. +//! - rent exemption is sponsored by the token program. //! - rent is 388 lamports per rent epoch (1.5 hours). -//! - once the account's lamports balance is insufficient, it is compressed to a compressed token account. +//! - once the account's lamports balance is insufficient, it is auto-compressed to a compressed token account. +//! - the accounts state is cryptographically preserved on the Solana ledger. //! - compressed tokens can be decompressed to a Light Token account. //! - configurable lamports per write (eg transfer) keep the Light Token account perpetually funded when used. So you don't have to worry about funding rent. -//! -//! ## Compressed Token Accounts -//! - are on Solana mainnet. -//! - are compressed accounts. -//! - can hold Light Mint and SPL Mint tokens. -//! - cost 5,000 lamports to create. -//! - are well suited for airdrops and reward distribution. +//! - users load a compressed account into a light account in-flight when using the account again. //! //! ## Light Mints //! - are on Solana devnet. //! - are Compressed accounts. //! - cost 15,000 lamports to create. //! - support `TokenMetadata`. +//! - have the same rent-config as light token accounts //! +//! ## Compressed Token Accounts +//! - are on Solana mainnet. +//! - are compressed accounts. +//! - can hold Light Mint and SPL Mint tokens. +//! - cost 5,000 lamports to create. +//! - are well suited for airdrops and reward distribution. //! //! For full program examples, see the [Light Token Examples](https://github.com/Lightprotocol/examples-light-token). -//! For detailed documentation, visit [zkcompression.com](https://www.zkcompression.com/). -//! For rust client development see [`light-client`](https://docs.rs/light-client). -//! For rust program testing see [`light-program-test`](https://docs.rs/light-program-test). -//! For local test validator with light system programs see [Light CLI](https://www.npmjs.com/package/@lightprotocol/zk-compression-cli). -//! //! +//! | Operation | Docs guide | GitHub example | +//! |-----------|-----------|----------------| +//! | `CreateAssociatedAccountCpi` | [create-ata](https://zkcompression.com/light-token/cookbook/create-ata) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/create-ata) | +//! | `CreateTokenAccountCpi` | [create-token-account](https://zkcompression.com/light-token/cookbook/create-token-account) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/create-token-account) | +//! | `CreateMintCpi` | [create-mint](https://zkcompression.com/light-token/cookbook/create-mint) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/create-mint) | +//! | `MintToCpi` | [mint-to](https://zkcompression.com/light-token/cookbook/mint-to) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/mint-to) | +//! | `MintToCheckedCpi` | [mint-to](https://zkcompression.com/light-token/cookbook/mint-to) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/mint-to-checked) | +//! | `BurnCpi` | [burn](https://zkcompression.com/light-token/cookbook/burn) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/burn) | +//! | `TransferCheckedCpi` | [transfer-checked](https://zkcompression.com/light-token/cookbook/transfer-checked) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/transfer-checked) | +//! | `TransferInterfaceCpi` | [transfer-interface](https://zkcompression.com/light-token/cookbook/transfer-interface) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/transfer-interface) | +//! | `ApproveCpi` | [approve-revoke](https://zkcompression.com/light-token/cookbook/approve-revoke) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/approve) | +//! | `RevokeCpi` | [approve-revoke](https://zkcompression.com/light-token/cookbook/approve-revoke) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/revoke) | +//! | `FreezeCpi` | [freeze-thaw](https://zkcompression.com/light-token/cookbook/freeze-thaw) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/freeze) | +//! | `ThawCpi` | [freeze-thaw](https://zkcompression.com/light-token/cookbook/freeze-thaw) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/thaw) | +//! | `CloseAccountCpi` | [close-token-account](https://zkcompression.com/light-token/cookbook/close-token-account) | [example](https://github.com/Lightprotocol/examples-light-token/tree/main/program-examples/anchor/basic-instructions/close-token-account) | //! //! ## Features //! diff --git a/sdk-libs/token-types/.cargo-rdme.toml b/sdk-libs/token-types/.cargo-rdme.toml new file mode 100644 index 0000000000..1e99b5cff9 --- /dev/null +++ b/sdk-libs/token-types/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-token-types" +heading-base-level = 0 diff --git a/sdk-libs/token-types/README.md b/sdk-libs/token-types/README.md new file mode 100644 index 0000000000..0b414dfec8 --- /dev/null +++ b/sdk-libs/token-types/README.md @@ -0,0 +1,15 @@ + + +# light-token-types + +Instruction data and account metadata types for compressed tokens. + +| Type | Description | +|------|-------------| +| [`TokenAccountMeta`](instruction::TokenAccountMeta) | Compressed token account metadata | +| [`BatchCompressInstructionData`](instruction::BatchCompressInstructionData) | Batch compress instruction data | +| [`CompressedTokenInstructionDataApprove`](instruction::CompressedTokenInstructionDataApprove) | Approve/delegation instruction data | +| [`PackedMerkleContext`](instruction::PackedMerkleContext) | Merkle tree context for proofs | +| [`DelegatedTransfer`](instruction::DelegatedTransfer) | Transfer with delegate as signer | + + diff --git a/sdk-libs/token-types/src/lib.rs b/sdk-libs/token-types/src/lib.rs index 16c3c4a72a..b0c16f53ea 100644 --- a/sdk-libs/token-types/src/lib.rs +++ b/sdk-libs/token-types/src/lib.rs @@ -1,3 +1,15 @@ +//! # light-token-types +//! +//! Instruction data and account metadata types for compressed tokens. +//! +//! | Type | Description | +//! |------|-------------| +//! | [`TokenAccountMeta`](instruction::TokenAccountMeta) | Compressed token account metadata | +//! | [`BatchCompressInstructionData`](instruction::BatchCompressInstructionData) | Batch compress instruction data | +//! | [`CompressedTokenInstructionDataApprove`](instruction::CompressedTokenInstructionDataApprove) | Approve/delegation instruction data | +//! | [`PackedMerkleContext`](instruction::PackedMerkleContext) | Merkle tree context for proofs | +//! | [`DelegatedTransfer`](instruction::DelegatedTransfer) | Transfer with delegate as signer | + pub mod account_infos; pub mod constants; pub mod error;