Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
[alias]
xtask = "run --package xtask --"

[resolver]
incompatible-rust-versions = "fallback"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does this do?


# On Windows
# ```
# cargo install -f cargo-binutils
Expand Down
78 changes: 8 additions & 70 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,7 @@ members = [
"sdk-tests/sdk-native-test",
"sdk-tests/sdk-v1-native-test",
"sdk-tests/sdk-token-test",
"sdk-tests/sdk-compressible-test",
"sdk-tests/sdk-light-token-test",
"sdk-tests/csdk-anchor-derived-test",
"sdk-tests/csdk-anchor-full-derived-test",
"forester-utils",
"forester",
Expand Down
8 changes: 4 additions & 4 deletions ctoken_for_payments.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ import {
createAssociatedTokenAccountInterfaceIdempotentInstruction,
getAssociatedTokenAddressInterface,
} from "@lightprotocol/compressed-token/unified";
import { CTOKEN_PROGRAM_ID } from "@lightprotocol/stateless.js";
import { LIGHT_TOKEN_PROGRAM_ID } from "@lightprotocol/stateless.js";

const ata = getAssociatedTokenAddressInterface(mint, recipient);

Expand All @@ -86,7 +86,7 @@ const tx = new Transaction().add(
ata,
recipient,
mint,
CTOKEN_PROGRAM_ID
LIGHT_TOKEN_PROGRAM_ID
)
);
```
Expand Down Expand Up @@ -203,15 +203,15 @@ import {
getAssociatedTokenAddressInterface,
createAssociatedTokenAccountInterfaceIdempotentInstruction,
} from "@lightprotocol/compressed-token/unified";
import { CTOKEN_PROGRAM_ID } from "@lightprotocol/stateless.js";
import { LIGHT_TOKEN_PROGRAM_ID } from "@lightprotocol/stateless.js";

const destinationAta = getAssociatedTokenAddressInterface(mint, recipient);
const createAtaIx = createAssociatedTokenAccountInterfaceIdempotentInstruction(
payer.publicKey,
destinationAta,
recipient,
mint,
CTOKEN_PROGRAM_ID
LIGHT_TOKEN_PROGRAM_ID
);

new Transaction().add(createAtaIx, transferIx);
Expand Down
4 changes: 0 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion program-libs/compressible/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ license = "MIT"
[features]
default = ["solana"]
solana = ["dep:solana-program-error", "light-compressed-account/solana", "light-account-checks/solana", "solana-sysvar", "solana-msg"]
anchor = ["anchor-lang", "light-compressed-account/anchor", "light-compressed-account/std", "light-account-checks/solana"]
anchor = ["anchor-lang", "light-compressed-account/anchor", "light-compressed-account/std", "light-account-checks/solana", "light-sdk-types/anchor"]
pinocchio = ["dep:pinocchio", "light-compressed-account/pinocchio", "light-account-checks/pinocchio"]
profile-program = []
profile-heap = ["dep:light-heap"]
Expand All @@ -32,6 +32,7 @@ light-program-profiler = { workspace = true }
light-heap = { workspace = true, optional = true }
light-account-checks = { workspace= true }
light-compressed-account = { workspace= true }
light-sdk-types = { workspace = true }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Find workspace root and check members
find . -name "Cargo.toml" -type f | head -3
cat Cargo.toml | grep -A 50 "^\[workspace\]" | head -60

Repository: Lightprotocol/light-protocol

Length of output: 1777


🏁 Script executed:

# Locate light-sdk-types definition
fd "light-sdk-types" --type d
find . -path "*/light-sdk-types/Cargo.toml" -type f

Repository: Lightprotocol/light-protocol

Length of output: 54


🏁 Script executed:

# Check the file under review and surrounding context
cat -n program-libs/compressible/Cargo.toml | sed -n '1,45p'

Repository: Lightprotocol/light-protocol

Length of output: 2164


🏁 Script executed:

# Look for CLAUDE.md files with governance rules
find . -name "CLAUDE.md" -type f | xargs ls -la
cat CLAUDE.md | head -100
cat sdk-libs/CLAUDE.md 2>/dev/null | head -100 || echo "No sdk-libs CLAUDE.md"
cat program-libs/CLAUDE.md 2>/dev/null | head -100 || echo "No program-libs CLAUDE.md"

Repository: Lightprotocol/light-protocol

Length of output: 6705


🏁 Script executed:

# Check light-sdk-types definition and contents
cat -n sdk-libs/sdk-types/Cargo.toml | head -30
echo "---"
cat sdk-libs/sdk-types/src/lib.rs | head -50

Repository: Lightprotocol/light-protocol

Length of output: 1984


🏁 Script executed:

# Check program-libs/compressible CLAUDE.md for context
cat program-libs/compressible/CLAUDE.md

Repository: Lightprotocol/light-protocol

Length of output: 2216


🏁 Script executed:

# Check what program-libs/compressible actually imports from light-sdk-types
rg "light-sdk-types|light_sdk_types" program-libs/compressible/src/ -A 2 -B 2

Repository: Lightprotocol/light-protocol

Length of output: 473


🏁 Script executed:

# Check if similar types exist in program-libs/token-interface
cat program-libs/token-interface/Cargo.toml | head -30
echo "---"
ls -la program-libs/token-interface/src/

Repository: Lightprotocol/light-protocol

Length of output: 1776


Move instruction types to program-libs instead of depending on sdk-libs.

Program libs must not depend on SDK libs—this violates the dependency boundary. The light-sdk-types crate is currently in sdk-libs, but program-libs/compressible needs PackedAddressTreeInfo from it. Either:

  1. Move light-sdk-types to program-libs (since it only depends on program-libs anyway), or
  2. Extract the instruction types to a shared location like program-libs/instruction-types or program-libs/compressed-account

Keeping program-libs dependencies unidirectional (inbound only from sdk-libs) is essential for clean separation of concerns.

🤖 Prompt for AI Agents
In `@program-libs/compressible/Cargo.toml` at line 35, The crate dependency is
inverted: program-libs/compressible depends on light-sdk-types from sdk-libs to
get PackedAddressTreeInfo, which breaks the intended dependency boundary; fix by
moving the instruction/type definitions (at least PackedAddressTreeInfo) into
program-libs (either relocate the entire light-sdk-types crate into program-libs
or extract the instruction types into a new program-libs crate such as
program-libs/instruction-types or program-libs/compressed-account) and then
update Cargo.toml in compressible to depend on that program-libs crate instead
of sdk-libs so program-libs stays independent of sdk-libs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find light-sdk-types in the workspace
echo "=== Finding light-sdk-types definition ==="
rg -l 'name\s*=\s*"light-sdk-types"' --glob 'Cargo.toml'

# Check the structure of the workspace
echo "=== Checking workspace structure ==="
find . -name "light-sdk-types" -type d | head -5

Repository: Lightprotocol/light-protocol

Length of output: 200


🏁 Script executed:

#!/bin/bash
# Once we find it, get its location and dependencies
CARGO_PATH=$(rg -l 'name\s*=\s*"light-sdk-types"' --glob 'Cargo.toml' | head -1)

if [ -n "$CARGO_PATH" ]; then
  echo "=== light-sdk-types Cargo.toml ==="
  cat "$CARGO_PATH"
  
  echo ""
  echo "=== Directory structure around light-sdk-types ==="
  dirname "$CARGO_PATH" | xargs ls -la
fi

Repository: Lightprotocol/light-protocol

Length of output: 1373


🏁 Script executed:

#!/bin/bash
# Check CLAUDE.md files in program-libs for dependency guidance
echo "=== CLAUDE.md files in program-libs ==="
find program-libs -name "CLAUDE.md" -type f | head -10

# Show relevant content from program-libs CLAUDE.md
if [ -f "program-libs/CLAUDE.md" ]; then
  echo "=== program-libs/CLAUDE.md content ==="
  cat "program-libs/CLAUDE.md" | head -100
fi

Repository: Lightprotocol/light-protocol

Length of output: 317


🏁 Script executed:

#!/bin/bash
# Find the exact path of light-sdk-types
echo "=== Exact location of light-sdk-types ==="
rg -l 'name\s*=\s*"light-sdk-types"' --glob 'Cargo.toml'

# Check what's in program-libs/compressible/CLAUDE.md
echo ""
echo "=== program-libs/compressible/CLAUDE.md ==="
cat program-libs/compressible/CLAUDE.md

# Also check the broader CLAUDE.md or guidelines
echo ""
echo "=== program-libs/compressible/docs/CLAUDE.md ==="
cat program-libs/compressible/docs/CLAUDE.md

Repository: Lightprotocol/light-protocol

Length of output: 2383


🏁 Script executed:

#!/bin/bash
# Check the current Cargo.toml of compressible to see all dependencies
echo "=== program-libs/compressible/Cargo.toml (full) ==="
cat program-libs/compressible/Cargo.toml | head -80

# Verify: is light-sdk-types in program-libs or sdk-libs?
echo ""
echo "=== Checking if light-sdk-types path ==="
fd -t d 'light-sdk-types' | head -5
</parameter>

Repository: Lightprotocol/light-protocol

Length of output: 2129


🏁 Script executed:

#!/bin/bash
# Find workspace root and list all crates to understand structure
echo "=== Root workspace.members ==="
rg '\[\[workspace\]\]' -A 50 'Cargo.toml' 2>/dev/null | head -60

# More direct: list Cargo.toml files with their package names
echo ""
echo "=== Package locations in workspace (sample) ==="
fd -t f 'Cargo.toml' -x grep -H 'name = "' {} \; | grep -E '(light-sdk-types|program-libs|sdk-libs)' | head -20

Repository: Lightprotocol/light-protocol

Length of output: 1365


🏁 Script executed:

#!/bin/bash
# Verify the dependency direction and check if there are already program-libs crates for types
echo "=== Looking for other program-libs type crates ==="
ls -la program-libs/ | grep -E 'type|interface'

# Check what light-sdk-types is actually used for in program-libs/compressible
echo ""
echo "=== How light-sdk-types is used in compressible ==="
rg 'light-sdk-types|use.*light_sdk_types' program-libs/compressible/src/ | head -20

Repository: Lightprotocol/light-protocol

Length of output: 335


🏁 Script executed:

#!/bin/bash
# Check if light-token-interface (program-libs tier) might be the right place for these types
echo "=== light-token-interface location and purpose ==="
head -50 program-libs/token-interface/src/lib.rs

# See if ValidityProof and PackedAddressTreeInfo mentioned in original review are in light-sdk-types
echo ""
echo "=== Types exported from light-sdk-types ==="
grep -E 'pub struct|pub enum' program-libs/sdk-types/src/lib.rs 2>/dev/null || grep -E 'pub struct|pub enum' sdk-libs/sdk-types/src/lib.rs | head -20

Repository: Lightprotocol/light-protocol

Length of output: 663


🏁 Script executed:

#!/bin/bash
# Check full light-sdk-types/src to see what instruction types are there
echo "=== light-sdk-types/src contents ==="
ls -la sdk-libs/sdk-types/src/

# Check if PackedAddressTreeInfo is defined there
echo ""
echo "=== Looking for PackedAddressTreeInfo definition ==="
rg 'PackedAddressTreeInfo' sdk-libs/sdk-types/src/ -B 2 -A 5 | head -30

Repository: Lightprotocol/light-protocol

Length of output: 1998


Move instruction types to program-libs tier—program-libs crates cannot depend on sdk-libs.

The light-sdk-types crate is located in sdk-libs/sdk-types/, which creates a dependency from program-libs/compressible upward into the SDK layer. This violates the dependency hierarchy: SDK libraries should depend on program libraries, not the reverse.

PackedAddressTreeInfo and similar instruction types are pure data structures that belong in the program-libs tier so that both programs and SDKs can use them. Per the established architecture, types needed by programs should be isolated in program-libs (similar to how light-token-interface handles token types), allowing SDKs to depend on them without creating backward dependencies.

Action: Move PackedAddressTreeInfo and related instruction types from sdk-libs/sdk-types/src/instruction/ to a new or existing program-libs type crate, then update dependencies accordingly.

🤖 Prompt for AI Agents
In `@program-libs/compressible/Cargo.toml` at line 35, The compressible crate
currently depends on light-sdk-types which creates an upward dependency; extract
the instruction types (e.g., PackedAddressTreeInfo and any sibling structs/enums
in sdk-libs/sdk-types/src/instruction/) into a new or existing program-libs
crate (name it something like program-types), update all source imports in
program and sdk code to use program-types::instruction::PackedAddressTreeInfo,
remove the light-sdk-types dependency from program-libs/compressible/Cargo.toml,
add the new program-types crate as a dependency in compressible's Cargo.toml,
and update any use/path references across the repo to point to the new crate so
no program-libs crate depends on sdk-libs.

aligned-sized = { workspace= true }
solana-sysvar = {workspace = true, optional = true}

Expand Down
15 changes: 15 additions & 0 deletions program-libs/compressible/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,18 @@ pub mod rent;
use anchor_lang::{AnchorDeserialize, AnchorSerialize};
#[cfg(not(feature = "anchor"))]
use borsh::{BorshDeserialize as AnchorDeserialize, BorshSerialize as AnchorSerialize};
use light_compressed_account::instruction_data::compressed_proof::ValidityProof;
use light_sdk_types::instruction::PackedAddressTreeInfo;

/// Proof data for instruction params when creating new compressed accounts.
/// Used in the INIT flow - pass directly to instruction data.
/// All accounts use the same address tree, so only one `address_tree_info` is needed.
#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)]
pub struct CreateAccountsProof {
/// The validity proof.
pub proof: ValidityProof,
/// Single packed address tree info (all accounts use same tree).
pub address_tree_info: PackedAddressTreeInfo,
/// Output state tree index for new compressed accounts.
pub output_state_tree_index: u8,
}
37 changes: 25 additions & 12 deletions programs/compressed-token/program/docs/ACCOUNTS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Accounts

- Compressed tokens can be decompressed to spl tokens. Spl tokens are not explicitly listed here.
- **description**
- **discriminator**
Expand All @@ -8,11 +9,12 @@
- **derivation:** (only for pdas)
- **associated instructions** (create, close, update)


## Solana Accounts

- The compressed token program uses

### CToken

- **description**
struct `CToken`
ctoken solana account with spl token compatible state layout
Expand Down Expand Up @@ -40,93 +42,104 @@
- **serialization example**
borsh and zero copy deserialization deserialize the compressible extension, spl serialization only deserialize the base token data.
zero copy: (always use in programs)

```rust
use light_token_interface::state::ctoken::CToken;
use light_token_interface::state::token::CToken;
use light_zero_copy::traits::{ZeroCopyAt, ZeroCopyAtMut};

let (token, _) = CToken::zero_copy_at(&account_data)?;
let (mut token, _) = CToken::zero_copy_at_mut(&mut account_data)?;
```

borsh: (always use in client non solana program code)

```rust
use borsh::BorshDeserialize;
use light_token_interface::state::ctoken::CToken;
use light_token_interface::state::token::CToken;

let token = CToken::deserialize(&mut &account_data[..])?;
```

spl serialization: (preferably use other serialization)

```rust
use spl_pod::bytemuck::pod_from_bytes;
use spl_token_2022::pod::PodAccount;

let pod_account = pod_from_bytes::<PodAccount>(&account_data[..165])?;
```


### Associated CToken

- **description**
struct `CToken`
ctoken solana account with spl token compatible state layout
- **derivation:**
seeds: [owner, ctoken_program_id, mint]
seeds: [owner, light_token_program_id, mint]
- the same as `CToken`


### Compressible Config

- owned by the LightRegistry program
- defined in path `program-libs/compressible/src/config.rs`
- crate: `light-compressible`


## Compressed Accounts

### Compressed Token

- compressed token account.
- version describes the hashing and the discriminator. (program-libs/token-interface/src/state/compressed_token/token_data_version.rs)
pub enum TokenDataVersion {
V1 = 1u8, // discriminator [2, 0, 0, 0, 0, 0, 0, 0], // 2 le (Poseidon hashed)
V2 = 2u8, // discriminator [0, 0, 0, 0, 0, 0, 0, 3], // 3 be (Poseidon hashed)
ShaFlat = 3u8, // discriminator [0, 0, 0, 0, 0, 0, 0, 4], // 4 be (Sha256 hash of borsh serialized data truncated to 31 bytes so that hash is less than be bn254 field size)
}
pub enum TokenDataVersion {
V1 = 1u8, // discriminator [2, 0, 0, 0, 0, 0, 0, 0], // 2 le (Poseidon hashed)
V2 = 2u8, // discriminator [0, 0, 0, 0, 0, 0, 0, 3], // 3 be (Poseidon hashed)
ShaFlat = 3u8, // discriminator [0, 0, 0, 0, 0, 0, 0, 4], // 4 be (Sha256 hash of borsh serialized data truncated to 31 bytes so that hash is less than be bn254 field size)
}

### Compressed Mint

## Extensions

The compressed token program supports multiple extensions defined in `program-libs/token-interface/src/state/extensions/`.

### Mint Extensions

#### TokenMetadata

- Mint extension, compatible with TokenMetadata extension of Token2022.
- Only available in compressed mints.
- Path: `program-libs/token-interface/src/state/extensions/token_metadata.rs`

### Token Account Extensions

#### Compressible

- Token account extension, Token2022 does not have an equivalent extension.
- Only available in ctoken solana accounts (decompressed ctokens), not in compressed token accounts.
- Stores compression info (rent sponsor, config, creation slot, etc.) for rent management.
- Path: `program-libs/token-interface/src/state/extensions/compressible.rs`

#### CompressedOnly

- Marker extension indicating the account can only exist in compressed form.
- Path: `program-libs/token-interface/src/state/extensions/compressed_only.rs`

#### Pausable

- Token account extension compatible with Token2022 PausableAccount extension.
- Path: `program-libs/token-interface/src/state/extensions/pausable.rs`

#### PermanentDelegate

- Token account extension compatible with Token2022 PermanentDelegate extension.
- Path: `program-libs/token-interface/src/state/extensions/permanent_delegate.rs`

#### TransferFee

- Token account extension compatible with Token2022 TransferFee extension.
- Path: `program-libs/token-interface/src/state/extensions/transfer_fee.rs`

#### TransferHook

- Token account extension compatible with Token2022 TransferHook extension.
- Path: `program-libs/token-interface/src/state/extensions/transfer_hook.rs`
Loading