refactor: separate compressed tokens from light-token#2199
refactor: separate compressed tokens from light-token#2199ananas-block merged 5 commits intomainfrom
Conversation
📝 WalkthroughWalkthroughAdds a new Changes
Sequence Diagram(s)(Skipped — changes are primarily crate/surface refactors and import/typedef migrations; control flow is not newly introduced.) Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
sdk-libs/token-sdk/src/error.rs (1)
6-62: Avoid ambiguousResultalias now thatLightTokenResultexists.Re-exporting
Result(backed byTokenSdkError) alongsideLightTokenResultmakes it easy for callers to pick the wrong error domain. Consider renaming the re-export to an explicit alias (e.g.,TokenSdkResult) or deprecating it.Proposed change
-pub use light_compressed_token_sdk::error::{Result, TokenSdkError}; +pub use light_compressed_token_sdk::error::{Result as TokenSdkResult, TokenSdkError};sdk-libs/token-sdk/src/instruction/create_associated_token_account.rs (1)
155-203: Consider a dedicated error for missing compressible config.When
COMPRESSIBLEis true and the config tuple is absent, returningInvalidAccountDataconflates caller misuse with on-chain data errors. A dedicated variant (e.g.,MissingCompressibleConfig) would make failures clearer to downstream callers.
🤖 Fix all issues with AI agents
In `@sdk-libs/compressed-token-sdk/src/compat.rs`:
- Around line 115-123: The current impl
From<light_token_interface::state::TokenData> for TokenData silently coerces
unknown account states to AccountState::Initialized; change this to a fallible
conversion by implementing TryFrom<light_token_interface::state::TokenData> for
TokenData (or changing the conversion to return Result<TokenData,
ProgramError>), call AccountState::try_from(data.state).map_err(|_|
ProgramError::InvalidAccountData) and propagate that error instead of unwrap_or,
and update any callers of the old From conversion to handle the Result (or
?-propagate the error) so invalid state bytes cause
ProgramError::InvalidAccountData rather than defaulting to Initialized.
In `@sdk-libs/compressed-token-sdk/src/error.rs`:
- Around line 93-104: The anchor-gated impl currently uses an unqualified
ProgramError which may resolve to solana_program_error::ProgramError; update the
impl From<TokenSdkError> for anchor builds to explicitly reference Anchor's
ProgramError (e.g., use anchor_lang::prelude::ProgramError::Custom or alias
anchor_lang::prelude::ProgramError to a local name) so the conversion
unambiguously constructs Anchor's error variant from TokenSdkError; adjust the
anchor-gated block around the impl to use that fully-qualified/aliased type
instead of the bare ProgramError.
49770eb to
179b060
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/decompress_full.rs (1)
259-275: Minor: RedundantTokenDefaultAccounts::default()calls.Both constructors call
TokenDefaultAccounts::default()twice. While not a bug, you could cache the result for slightly cleaner code:let defaults = TokenDefaultAccounts::default(); Self { compressed_token_program: defaults.compressed_token_program, cpi_authority_pda: defaults.cpi_authority_pda, // ... }This is a nitpick—feel free to leave as-is if the compiler optimizes it away or if you prefer the current explicit style.
sdk-libs/token-client/src/actions/mint_action.rs (1)
108-108: Mixed import paths:light_tokenvslight_compressed_token_sdk.This line still uses
light_token::instruction::derive_token_atawhile the file's other imports have migrated tolight_compressed_token_sdk. While this works becauselight-token-sdkre-exports fromlight-compressed-token-sdk, it creates inconsistency within the same file.Consider whether
derive_token_ata(alias forderive_associated_token_account) should also be imported from the compressed-token SDK path for consistency, or if this is intentionally kept at the higher-level SDK since it deals with Light Token accounts rather than compressed tokens specifically.sdk-libs/token-sdk/src/pack.rs (1)
42-54: Note:TokenDataWithMerkleContextduplicated between crates.This struct and its
hash()method are defined both here and inlight_compressed_token_sdk::compat. While the implementations are identical, consider whethertoken-sdkshould re-exportTokenDataWithMerkleContextfromcompressed-token-sdkas well, to maintain a single definition.Not blocking—this could be addressed in a follow-up cleanup.
sdk-libs/token-sdk/src/error.rs (1)
14-40: Duplicate error variants with different codes will complicate debugging.All 11
LightTokenErrorvariants have identically-named counterparts inTokenSdkError(from the relevant code snippet):
Variant LightTokenError TokenSdkError SplInterfaceRequired17500 17020 InvalidAccountData17509 17013 SerializationError17510 17002 ... ... ... When debugging, seeing error code
17500vs17020for the same semantic issue (SplInterfaceRequired) is confusing. Consider either:
- Distinct naming - prefix high-level variants (e.g.,
HighLevelSplInterfaceRequired) to clarify origin- Error wrapping - wrap
TokenSdkErrorinstead of duplicating variants:pub enum LightTokenError { #[error(transparent)] CompressedToken(#[from] TokenSdkError), // ... only truly new high-level errors }
- Remove duplicates - if the high-level SDK always surfaces the underlying error, just re-export without duplication
sdk-libs/token-sdk/src/instruction/create_associated_token_account.rs (1)
101-117: Naming collision with semantic mismatch between instruction builders and CPI wrappers.The same function names have different semantics:
Function Name Signature (Lines 102-117) Signature (Lines 408-493) create_associated_token_accountCreates basic ATA Creates compressible ATA via CPI create_associated_token_account_idempotentCreates basic ATA Creates compressible ATA via CPI While Rust allows this due to different generic parameters, calling
create_associated_token_accountcould silently create the wrong account type depending on context. This is a footgun for API consumers.Consider renaming the CPI wrappers to be explicit:
Suggested rename for clarity
-pub fn create_associated_token_account<'info>( +pub fn create_compressible_associated_token_account_cpi<'info>( payer: AccountInfo<'info>, // ... ) -> std::result::Result<(), solana_program_error::ProgramError> { -pub fn create_associated_token_account_idempotent<'info>( +pub fn create_compressible_associated_token_account_idempotent_cpi<'info>( payer: AccountInfo<'info>, // ... ) -> std::result::Result<(), solana_program_error::ProgramError> {Also applies to: 406-493
🤖 Fix all issues with AI agents
In `@sdk-libs/compressed-token-sdk/src/compat.rs`:
- Around line 83-94: The hash() method on TokenDataWithMerkleContext currently
returns HasherError::EmptyInput when the
compressed_account.compressed_account.data.discriminator is present but not
equal to the sha-flat marker ([0,0,0,0,0,0,0,4]); change this to return a more
descriptive error by adding an enum variant to HasherError (e.g.,
UnsupportedVersion or InvalidDiscriminator) and return that variant in the match
arm that currently yields Err(HasherError::EmptyInput) while leaving the
successful path calling token_data.hash_sha_flat() unchanged.
In `@sdk-libs/token-client/src/instructions/mint_to_compressed.rs`:
- Around line 66-67: Replace the verbose fully-qualified type for
spl_interface_pda with a top-level import: add use
light_compressed_token_sdk::spl_interface::SplInterfacePda; at the top of the
file and change the declaration let spl_interface_pda:
Option<light_compressed_token_sdk::spl_interface::SplInterfacePda> = None; to
use the imported symbol (Option<SplInterfacePda>) so the variable
spl_interface_pda references SplInterfacePda directly.
In `@sdk-libs/token-sdk/src/compressible/decompress_runtime.rs`:
- Around line 56-58: The file repeatedly uses the long path
light_compressed_token_sdk::compressed_token::decompress_full::...; add a
single-use import for the items used (e.g., DecompressFullIndices and
decompress_full_token_accounts_with_indices) near the top with the other use
statements, then replace fully-qualified occurrences of
light_compressed_token_sdk::compressed_token::decompress_full::DecompressFullIndices
and
light_compressed_token_sdk::compressed_token::decompress_full::decompress_full_token_accounts_with_indices
with the short names DecompressFullIndices and
decompress_full_token_accounts_with_indices throughout the file (locations
around where token_decompress_indices is created and the calls at the other
reported ranges).
♻️ Duplicate comments (2)
sdk-libs/compressed-token-sdk/src/compat.rs (1)
115-126: Silent coercion of unknown account states persists.The
From<light_token_interface::state::TokenData>impl at line 122 usesunwrap_or(AccountState::Initialized)which silently masks corrupted or unknown state values. This was flagged in a previous review—consider implementingTryFrominstead to propagateProgramError::InvalidAccountDatafor invalid state bytes.sdk-libs/compressed-token-sdk/src/error.rs (1)
93-98: DisambiguateProgramErrorin anchor builds.The anchor-gated impl references
ProgramError::Customwhich resolves tosolana_program_error::ProgramErrorfrom the module-level import. For clarity and to avoid potential divergence, prefer fully qualifying asanchor_lang::prelude::ProgramError::Custom(e.into()).
07e5189 to
4618eb7
Compare
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
sdk-libs/program-test/Cargo.toml (1)
36-37: Remove redundantversionspecifications on workspace dependencies.When
workspace = trueis set, Cargo retrieves the version from the workspace root definition—the explicit version here is ignored and triggers CI lint warnings. In the workspace root,light-registryandlight-compressed-tokenare already configured withversion = "2.0.0", so these specifications are unnecessary.Suggested fix
-light-registry = { workspace = true, version = "2.0.0", features = ["cpi"], optional = true } -light-compressed-token = { workspace = true, version = "2.0.0", features = ["cpi"], optional = true } +light-registry = { workspace = true, features = ["cpi"], optional = true } +light-compressed-token = { workspace = true, features = ["cpi"], optional = true }
🤖 Fix all issues with AI agents
In `@sdk-libs/compressed-token-sdk/src/spl_interface.rs`:
- Around line 55-62: The public CreateSplInterfacePda struct allows inconsistent
manual construction (e.g., index>0 with existing_spl_interface_pda=None) which
will panic on the unwrap in instruction(); fix by making CreateSplInterfacePda's
fields private and expose safe constructors (e.g., new_with_existing(...) and
new_without_existing(...)) that enforce the invariant, or alternatively change
instruction() to return Result<Instruction, TokenSdkError> and replace the
unwrap() with a propagated error (or an expect() with a clear message) so
inconsistent state is handled without panicking; update any call sites that
construct the struct directly to use the new constructors or handle the Result
from instruction().
In `@sdk-libs/compressed-token-sdk/src/utils.rs`:
- Around line 73-77: The listed imports (REGISTERED_PROGRAM_PDA,
ACCOUNT_COMPRESSION_AUTHORITY_PDA, ACCOUNT_COMPRESSION_PROGRAM_ID,
CPI_AUTHORITY_PDA, LIGHT_SYSTEM_PROGRAM_ID, NOOP_PROGRAM_ID, and
LIGHT_COMPRESSED_TOKEN_PROGRAM_ID) are declared mid-file; move their use
statements into the file's main import block alongside the existing top imports
(join them with the imports at lines 3-11) and remove the duplicate import block
currently at lines 73-77 so all external dependencies are declared together at
the top of the file.
In `@sdk-libs/token-client/Cargo.toml`:
- Line 17: The token-client crate currently depends on another SDK crate
light-compressed-token-sdk (line with light-compressed-token-sdk = { workspace =
true }); remove that dependency and move the shared types/utilities it consumes
into a program-libs crate (create or reuse light-token-interface) so
token-client only imports from program-libs. Concretely: extract the exported
types, PDA helpers, instruction constructors, and any shared utilities from
light-compressed-token-sdk into light-token-interface, update token-client's
Cargo.toml to remove light-compressed-token-sdk and add a dependency on
light-token-interface, then update all use/import paths in token-client to
reference the new light-token-interface symbols (types, functions, modules). Run
cargo build/tests to ensure no remaining references to
light-compressed-token-sdk and adjust visibility/feature flags in
light-token-interface so all former usages compile.
In `@sdk-libs/token-sdk/Cargo.toml`:
- Around line 9-16: The cpi-context feature in Cargo.toml currently only enables
"light-sdk/cpi-context" but does not propagate to "light-compressed-token-sdk";
update the cpi-context feature entry so it also includes
"light-compressed-token-sdk/cpi-context" (mirroring how features like anchor and
idl-build propagate) so that enabling cpi-context on this crate automatically
enables the corresponding feature in the light-compressed-token-sdk crate.
In `@sdk-libs/token-sdk/src/compressible/mod.rs`:
- Around line 5-16: The struct AccountInfoToCompress currently derives
AnchorSerialize/AnchorDeserialize (aliased to Borsh) but contains
solana_account_info::AccountInfo which is not serializable; remove the derives
from AccountInfoToCompress (drop #[derive(Debug, Clone, AnchorSerialize,
AnchorDeserialize)]) and keep it as a plain runtime container, or alternatively
extract any fields that must be serialized into a separate serializable struct
and use that for (de)serialization; update references to use the
non-serializable AccountInfoToCompress where runtime-only data is needed and the
new serializable struct where persistence/IPC is required.
In `@sdk-libs/token-sdk/src/constants.rs`:
- Around line 6-12: The local redefinition of LIGHT_TOKEN_PROGRAM_ID conflicts
with the glob re-export from light_compressed_token_sdk::constants::* (which
already defines LIGHT_TOKEN_PROGRAM_ID), causing a duplicate binding; either
remove the local LIGHT_TOKEN_PROGRAM_ID constant so both SDKs share the upstream
value, or replace the glob re-export with an explicit import list that omits
LIGHT_TOKEN_PROGRAM_ID (export other constants from
light_compressed_token_sdk::constants::* explicitly) so the local constant
remains a deliberate override—adjust the use statement and/or delete the local
pub const LIGHT_TOKEN_PROGRAM_ID accordingly.
In `@sdk-libs/token-sdk/src/instruction/create_mints.rs`:
- Around line 14-17: The file create_mints.rs imports MintActionMetaConfig,
MintActionMetaConfigCpiWrite, and
get_mint_action_instruction_account_metas_cpi_write from
light_compressed_token_sdk which violates sdk-libs dependency rules; move the
definitions of MintActionMetaConfig and MintActionMetaConfigCpiWrite and the
function get_mint_action_instruction_account_metas_cpi_write into the
light-token-interface program-lib, then update create_mints.rs to import those
symbols from light-token-interface instead of light_compressed_token_sdk and add
light-token-interface as the dependency in Cargo.toml for this crate so the SDK
only depends on program-libs.
In `@sdk-libs/token-sdk/src/instruction/mod.rs`:
- Around line 215-224: Re-export compression_authority_pda alongside the other
PDA helpers by adding compression_authority_pda into the public re-export block
(the pub use crate::{ constants::{ ... } , ... } statement) next to config_pda
and rent_sponsor_pda so the module facade consistently exposes the PDA helper;
update the constants re-export list to include compression_authority_pda and run
a build/check to ensure the symbol is in scope.
♻️ Duplicate comments (3)
sdk-libs/compressed-token-sdk/src/compat.rs (2)
115-126: Silent coercion of unknown account states masks data corruption.This was flagged in a previous review and remains unaddressed. The
unwrap_or(AccountState::Initialized)at line 122 will silently accept invalidstatevalues, potentially allowing operations on corrupted accounts to proceed when they should fail.The recommended fix is to change this to a fallible
TryFromconversion that propagatesProgramError::InvalidAccountData.
83-94: Hash method error semantics could be clearer.This was noted in a previous review. Returning
HasherError::EmptyInputwhen the discriminator doesn't match[0,0,0,0,0,0,0,4]is semantically imprecise — the input isn't empty, it's an unsupported version. A dedicated error variant would better communicate the failure reason.sdk-libs/compressed-token-sdk/src/error.rs (1)
93-98: AmbiguousProgramErrorreference in anchor-gated impl.This was flagged in a previous review. In the anchor-gated impl,
ProgramError::Customresolves tosolana_program_error::ProgramError(from the import at line 7), not Anchor'sProgramError. While they're currently the same type, explicitly usinganchor_lang::prelude::ProgramError::Customwould be clearer and more robust against future divergence.
| pub struct CreateSplInterfacePda { | ||
| pub fee_payer: Pubkey, | ||
| pub mint: Pubkey, | ||
| pub token_program: Pubkey, | ||
| pub spl_interface_pda: Pubkey, | ||
| pub existing_spl_interface_pda: Option<Pubkey>, | ||
| pub index: u8, | ||
| } |
There was a problem hiding this comment.
Potential panic if struct is constructed manually with inconsistent state.
The struct fields are public, which means a consumer could bypass the constructors and create an instance with index > 0 but existing_spl_interface_pda = None. This would cause an unwrap() panic at line 123.
Consider either:
- Making fields private and exposing only through constructors, or
- Using
expect()with a descriptive message, or - Returning
Result<Instruction, TokenSdkError>frominstruction()
🔧 Suggested defensive fix
pub fn instruction(self) -> Instruction {
let cpi_authority = Pubkey::from(CPI_AUTHORITY);
if self.index == 0 {
// CreateTokenPool instruction
Instruction {
program_id: Pubkey::from(LIGHT_TOKEN_PROGRAM_ID),
accounts: vec![
AccountMeta::new(self.fee_payer, true),
AccountMeta::new(self.spl_interface_pda, false),
AccountMeta::new_readonly(Pubkey::default(), false), // system_program
AccountMeta::new(self.mint, false),
AccountMeta::new_readonly(self.token_program, false),
AccountMeta::new_readonly(cpi_authority, false),
],
data: CREATE_TOKEN_POOL.to_vec(),
}
} else {
// AddTokenPool instruction
let mut data = ADD_TOKEN_POOL.to_vec();
data.push(self.index);
Instruction {
program_id: Pubkey::from(LIGHT_TOKEN_PROGRAM_ID),
accounts: vec![
AccountMeta::new(self.fee_payer, true),
AccountMeta::new(self.spl_interface_pda, false),
- AccountMeta::new_readonly(self.existing_spl_interface_pda.unwrap(), false),
+ AccountMeta::new_readonly(
+ self.existing_spl_interface_pda
+ .expect("existing_spl_interface_pda required when index > 0"),
+ false,
+ ),
AccountMeta::new_readonly(Pubkey::default(), false), // system_program
AccountMeta::new(self.mint, false),
AccountMeta::new_readonly(self.token_program, false),
AccountMeta::new_readonly(cpi_authority, false),
],
data,
}
}
}Also applies to: 120-131
🤖 Prompt for AI Agents
In `@sdk-libs/compressed-token-sdk/src/spl_interface.rs` around lines 55 - 62, The
public CreateSplInterfacePda struct allows inconsistent manual construction
(e.g., index>0 with existing_spl_interface_pda=None) which will panic on the
unwrap in instruction(); fix by making CreateSplInterfacePda's fields private
and expose safe constructors (e.g., new_with_existing(...) and
new_without_existing(...)) that enforce the invariant, or alternatively change
instruction() to return Result<Instruction, TokenSdkError> and replace the
unwrap() with a propagated error (or an expect() with a clear message) so
inconsistent state is handled without panicking; update any call sites that
construct the struct directly to use the new constructors or handle the Result
from instruction().
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Fix all issues with AI agents
In `@sdk-libs/compressed-token-sdk/src/utils.rs`:
- Around line 68-72: The struct AccountInfoToCompress currently derives
AnchorSerialize and AnchorDeserialize but contains AccountInfo<'info>, which
doesn't implement those traits; either remove the
AnchorSerialize/AnchorDeserialize derives from AccountInfoToCompress to fix the
compile error, or if you need wire serialization change the field to an
Account<'info, T> (a concrete account type) and then keep the serialization
derives; locate AccountInfoToCompress in utils.rs and apply one of these two
changes accordingly.
- Around line 93-105: The default impl for TokenDefaultAccounts uses
Pubkey::default() for the system_program field; replace that with the explicit
Solana system program constant to clarify intent by setting system_program to
solana_program::system_program::ID in the TokenDefaultAccounts::default()
implementation (update imports if necessary to reference
solana_program::system_program::ID).
In `@sdk-libs/token-client/src/actions/mint_action.rs`:
- Around line 5-7: The new direct import of create_compressed_mint (and its
helpers derive_mint_compressed_address and find_mint_address) from
light_compressed_token_sdk violates the sdk-libs dependency policy; update the
code to consume these helpers via an approved program-lib re-export (add or use
a function in the program-lib that wraps/re-exports
derive_mint_compressed_address and find_mint_address) or, if unavoidable, add an
explicit documented exception to the repository policy documenting why
light_compressed_token_sdk must be imported directly and who approved it; ensure
references in mint_action.rs are changed to call the program-lib wrapper (or
annotated exception) rather than importing from light_compressed_token_sdk
directly.
In `@sdk-libs/token-sdk/Cargo.toml`:
- Around line 10-16: The cpi-context feature in this Cargo.toml currently lists
"light-sdk/cpi-context" but does not propagate that feature to the dependent
crate "light-compressed-token-sdk", so cfg(feature="cpi-context") in
light-compressed-token-sdk remains inactive; update the cpi-context feature
array to include "light-compressed-token-sdk/cpi-context" (i.e., add the symbol
"light-compressed-token-sdk/cpi-context" to the cpi-context feature in this
file) and make the corresponding identical change for the other affected feature
blocks/ crates noted (the same cpi-context feature entries referenced on the
other lines) so consumers enabling cpi-context on the top-level crate
transitively enable it in light-compressed-token-sdk.
In `@sdk-libs/token-sdk/src/compressible/mod.rs`:
- Around line 5-16: The AccountInfoToCompress struct currently derives
AnchorSerialize/AnchorDeserialize which is invalid because AccountInfo cannot be
serialized; remove the #[derive(...)] (AnchorSerialize, AnchorDeserialize) from
the AccountInfoToCompress struct to make it a runtime-only container, and if you
actually need a serializable payload create a separate POD wrapper (e.g.,
SerializableAccountInfo) that extracts owned fields like key, is_signer,
is_writable, owner and implement/derive AnchorSerialize/AnchorDeserialize on
that wrapper instead; locate the struct AccountInfoToCompress and remove the
serialize/deserialize derives or replace its usage where a serializable type is
required with the new wrapper.
In `@sdk-libs/token-sdk/src/constants.rs`:
- Around line 6-13: The file currently re-exports everything from
light_compressed_token_sdk::constants::* while also defining a local constant
LIGHT_TOKEN_PROGRAM_ID, causing a duplicate symbol; remove the local duplicate
definition or stop wildcard re-exporting and instead explicitly re-export only
the needed constants from light_compressed_token_sdk::constants (or rename the
local constant) so that LIGHT_TOKEN_PROGRAM_ID is defined once; locate the
conflict around the pub use light_compressed_token_sdk::constants::* and the
local LIGHT_TOKEN_PROGRAM_ID constant in constants.rs and apply the chosen fix.
In `@sdk-libs/token-sdk/src/instruction/transfer_from_spl.rs`:
- Around line 2-7: This file imports transfer2 types from
light_compressed_token_sdk (create_transfer2_instruction,
Transfer2AccountsMetaConfig, Transfer2Config, Transfer2Inputs, CTokenAccount2)
which violates sdk-libs dependency rules; fix by moving the shared
transfer2/CTokenAccount2 type definitions into a program-lib interface crate
(e.g., light-token-interface) or into an existing program-lib, update this
crate's Cargo.toml to depend on that program-lib instead of
light_compressed_token_sdk, and replace the imports in transfer_from_spl.rs to
reference the new interface crate's module paths (ensure function/type names
remain create_transfer2_instruction, Transfer2AccountsMetaConfig,
Transfer2Config, Transfer2Inputs, CTokenAccount2).
In `@sdk-libs/token-sdk/src/utils.rs`:
- Around line 3-10: Remove the duplicate import of LIGHT_TOKEN_PROGRAM_ID from
light_sdk_types and consolidate on the single source from crate::constants
(currently imported as PROGRAM_ID); delete the `use
light_sdk_types::LIGHT_TOKEN_PROGRAM_ID;` line and update any usage of
LIGHT_TOKEN_PROGRAM_ID in this module (e.g., the occurrence referenced around
where PROGRAM_ID is used) to use the existing PROGRAM_ID symbol so there’s only
one canonical import.
♻️ Duplicate comments (7)
sdk-libs/compressed-token-sdk/src/error.rs (1)
93-98: Disambiguate Anchor ProgramError construction.
In the anchor-gated impl,ProgramError::Customresolves to the importedsolana_program_error::ProgramError. Prefer the fully qualified Anchor type to avoid ambiguity.🧭 Proposed tweak
#[cfg(feature = "anchor")] impl From<TokenSdkError> for anchor_lang::prelude::ProgramError { fn from(e: TokenSdkError) -> Self { - ProgramError::Custom(e.into()) + anchor_lang::prelude::ProgramError::Custom(e.into()) } }In anchor_lang, is prelude::ProgramError a type alias to solana_program_error::ProgramError? If not, is ProgramError::Custom the correct constructor for Anchor’s ProgramError conversions?sdk-libs/client/src/interface/load_accounts.rs (1)
6-11: Same sdk-libs dependency layering concern.This introduces the same sdk-lib → sdk-lib dependency noted earlier. Please resolve consistently across sdk-libs. As per coding guidelines, ...
sdk-libs/token-sdk/src/instruction/decompress_mint.rs (1)
4-16: Same sdk-libs dependency layering concern.This is the same sdk-lib → sdk-lib dependency introduced elsewhere and should be resolved uniformly. As per coding guidelines, ...
sdk-libs/token-client/src/actions/transfer2/ctoken_to_spl.rs (1)
5-8: Same sdk-libs dependency layering concern.This is the same sdk-lib → sdk-lib dependency introduced elsewhere and should be resolved consistently. As per coding guidelines, ...
sdk-libs/token-sdk/src/instruction/transfer_interface.rs (1)
1-1: Same sdk-libs dependency layering concern.This introduces the same sdk-lib → sdk-lib dependency noted earlier. As per coding guidelines, ...
sdk-libs/compressed-token-sdk/src/compat.rs (2)
115-126: Silent coercion of invalid account state remains unaddressed.Line 122 still uses
unwrap_or(AccountState::Initialized)which masks corrupted or invalid state bytes. This was flagged in a prior review. Ifdata.statecontains an unexpected value (e.g.,2or255), you silently produce a validTokenDatawithInitializedstate instead of surfacing the error.Consider switching to
TryFromto propagate errors:🔧 Suggested change
-impl From<light_token_interface::state::TokenData> for TokenData { - fn from(data: light_token_interface::state::TokenData) -> Self { - Self { +impl TryFrom<light_token_interface::state::TokenData> for TokenData { + type Error = ProgramError; + + fn try_from(data: light_token_interface::state::TokenData) -> Result<Self, Self::Error> { + Ok(Self { mint: Pubkey::new_from_array(data.mint.to_bytes()), owner: Pubkey::new_from_array(data.owner.to_bytes()), amount: data.amount, delegate: data.delegate.map(|d| Pubkey::new_from_array(d.to_bytes())), - state: AccountState::try_from(data.state).unwrap_or(AccountState::Initialized), + state: AccountState::try_from(data.state)?, tlv: data.tlv, - } + }) } }
83-94: Consider a more descriptive error variant for unsupported discriminators.Both the missing-data case (line 92) and the wrong-discriminator case (line 89) return
HasherError::EmptyInput. While this works, it conflates two distinct failure modes. A variant likeUnsupportedVersionorInvalidDiscriminatorwould communicate the actual issue more clearly to callers debugging hash failures.This is a minor clarity improvement—not blocking.
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@sdk-libs/token-client/src/instructions/mint_to_compressed.rs`:
- Around line 6-14: This import from light_compressed_token_sdk violates
sdk-libs -> program-libs-only boundaries; remove direct dependency and instead
have a program-lib re-export the needed symbols (e.g., re-export
derive_mint_from_spl_mint, create_mint_to_compressed_instruction,
DecompressedMintConfig, MintToCompressedInputs, SplInterfacePda) from a shared
interface crate (suggested name: light-token-interface), update this file's use
statements to import those re-exports, and update Cargo.toml to depend on that
program-lib rather than light_compressed_token_sdk; alternatively, if a
documented exception is required, add an explicit rationale in the repo policy
and a TODO comment referencing the exception while keeping current imports until
the re-export is implemented.
In `@sdk-libs/token-sdk/Cargo.toml`:
- Around line 11-16: The Cargo feature "v1" in token-sdk is a dangling stub that
references light-compressed-token-sdk/v1 but has no implementation in downstream
crates; either remove the v1 feature and its propagation from
token-sdk/Cargo.toml to avoid exposing a non-functional public API, or implement
full v1 support by adding a v1 feature to light-token-types and
light-token-interface (e.g., v1 = []), updating token-sdk's v1 to propagate to
those crates (and to light-compressed-token-sdk/v1), and then audit light-sdk
and light-sdk-types (currently pinned to ["v2"]) to decide if they should be
made version-switchable or left pinned to v2.
- Line 33: The Cargo.toml currently adds an SDK-to-SDK dependency on
light-compressed-token-sdk which violates the SDK layering rule; remove that
dependency and either (A) move the shared constants, error types, SPL interface
and utilities currently consumed by light-token into a program-lib (for example
extend or add them to light-token-interface) and update light-token and this
crate to depend on the program-lib instead, or (B) if this dependency is
intentional, add an explicit documented exception to the repository policy
(CLAUDE.md) and justify it in this crate's README/Cargo manifest comments;
reference the crate name light-compressed-token-sdk, the consumer crate
light-token, and the program-lib candidate light-token-interface when making the
change.
In `@sdk-libs/token-sdk/src/compressible/decompress_runtime.rs`:
- Around line 3-5: The import in decompress_runtime.rs pulls
DecompressFullIndices and decompress_full_token_accounts_with_indices from
light_compressed_token_sdk which creates an sdk-libs-to-sdk-libs dependency;
move the definitions of DecompressFullIndices and
decompress_full_token_accounts_with_indices into program-libs/token-interface so
both light-compressed-token-sdk and light-token-sdk can depend on them, then
update decompress_runtime.rs to import these symbols from the new
program-libs/token-interface crate (replace the current use of
light_compressed_token_sdk::compressed_token::decompress_full with the
corresponding module path in program-libs/token-interface) and remove the old
cross-sdklib dependency.
♻️ Duplicate comments (1)
sdk-libs/compressed-token-sdk/src/utils.rs (1)
93-104: Prefer explicit System Program ID overPubkey::default()for clarity.
This is the same readability nit flagged earlier; still applies here.♻️ Suggested tweak
+use solana_program::system_program::ID as SYSTEM_PROGRAM_ID; ... impl Default for TokenDefaultAccounts { fn default() -> Self { Self { light_system_program: Pubkey::from(LIGHT_SYSTEM_PROGRAM_ID), registered_program_pda: Pubkey::from(REGISTERED_PROGRAM_PDA), noop_program: Pubkey::from(NOOP_PROGRAM_ID), account_compression_authority: Pubkey::from(ACCOUNT_COMPRESSION_AUTHORITY_PDA), account_compression_program: Pubkey::from(ACCOUNT_COMPRESSION_PROGRAM_ID), self_program: Pubkey::from(LIGHT_COMPRESSED_TOKEN_PROGRAM_ID), cpi_authority_pda: Pubkey::from(CPI_AUTHORITY_PDA), - system_program: Pubkey::default(), + system_program: SYSTEM_PROGRAM_ID, compressed_token_program: Pubkey::from(LIGHT_TOKEN_PROGRAM_ID), } } }
| use light_compressed_token_sdk::{ | ||
| compressed_token::{ | ||
| create_compressed_mint::derive_mint_from_spl_mint, | ||
| mint_to_compressed::{ | ||
| create_mint_to_compressed_instruction, DecompressedMintConfig, MintToCompressedInputs, | ||
| }, | ||
| }, | ||
| spl_interface::SplInterfacePda, | ||
| }; |
There was a problem hiding this comment.
Validate SDK layer boundaries for the new light_compressed_token_sdk dependency.
This file is under sdk-libs/, but the new import pulls in another sdk-lib crate (light_compressed_token_sdk). If the boundary rule still applies, consider re-exporting the needed types/functions via a program-lib (e.g., light-token-interface) or documenting an explicit exception for sdk-lib→sdk-lib dependencies. As per coding guidelines, sdk-libs should depend only on program-libs, light-prover-client, and external crates.
Also applies to: 69-69
🤖 Prompt for AI Agents
In `@sdk-libs/token-client/src/instructions/mint_to_compressed.rs` around lines 6
- 14, This import from light_compressed_token_sdk violates sdk-libs ->
program-libs-only boundaries; remove direct dependency and instead have a
program-lib re-export the needed symbols (e.g., re-export
derive_mint_from_spl_mint, create_mint_to_compressed_instruction,
DecompressedMintConfig, MintToCompressedInputs, SplInterfacePda) from a shared
interface crate (suggested name: light-token-interface), update this file's use
statements to import those re-exports, and update Cargo.toml to depend on that
program-lib rather than light_compressed_token_sdk; alternatively, if a
documented exception is required, add an explicit rationale in the repo policy
and a TODO comment referencing the exception while keeping current imports until
the re-export is implemented.
| v1 = ["light-compressed-token-sdk/v1"] | ||
| anchor-discriminator = ["light-sdk/anchor-discriminator", "light-compressed-token-sdk/anchor-discriminator"] | ||
| anchor = ["anchor-lang", "light-token-types/anchor", "light-token-interface/anchor", "light-compressed-token-sdk/anchor", "dep:light-sdk-macros"] | ||
| # idl-build feature enables IDL generation for client-side tooling and SDK generation | ||
| idl-build = ["anchor", "anchor-lang/idl-build", "light-sdk/idl-build"] | ||
| cpi-context = ["light-sdk/cpi-context"] | ||
| idl-build = ["anchor", "anchor-lang/idl-build", "light-sdk/idl-build", "light-compressed-token-sdk/idl-build"] | ||
| cpi-context = ["light-sdk/cpi-context", "light-compressed-token-sdk/cpi-context"] |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, locate and inspect the token-sdk Cargo.toml
echo "=== sdk-libs/token-sdk/Cargo.toml ==="
cat -n sdk-libs/token-sdk/Cargo.toml | head -50
echo -e "\n=== Check for v1 features in related crates ==="
# Find all Cargo.toml files in sdk-libs and program-libs that mention token or sdk
find sdk-libs program-libs -name "Cargo.toml" -type f | sort | while read f; do
# Only check if file contains "token" or "sdk" or "interface" in path or contains v1 feature
if echo "$f" | grep -qE "(token|sdk|interface|compressed)" || rg -q "^\s*v1\s*=" "$f" 2>/dev/null; then
echo -e "\n--- $f ---"
rg -A 2 "^\s*\[features\]" "$f" | head -20
fi
doneRepository: Lightprotocol/light-protocol
Length of output: 200
🏁 Script executed:
#!/bin/bash
# Check light-compressed-token-sdk specifically
echo "=== Checking light-compressed-token-sdk in program-libs ==="
find program-libs -path "*compressed-token*" -name "Cargo.toml" -type f | while read f; do
echo -e "\n--- $f ---"
cat -n "$f" | head -60
doneRepository: Lightprotocol/light-protocol
Length of output: 131
🏁 Script executed:
#!/bin/bash
# Look for CLAUDE.md files that provide guidance on feature handling
echo "=== Checking for CLAUDE.md guidance ==="
find sdk-libs program-libs -name "CLAUDE.md" -type f | while read f; do
echo -e "\n--- $f ---"
cat "$f" 2>/dev/null | grep -i -E "feature|v1|v2|layout" | head -10
doneRepository: Lightprotocol/light-protocol
Length of output: 1265
🏁 Script executed:
#!/bin/bash
# Read the actual token-sdk Cargo.toml file
echo "=== sdk-libs/token-sdk/Cargo.toml (full file) ==="
cat sdk-libs/token-sdk/Cargo.toml
echo -e "\n=== Search for all v1 feature definitions ==="
rg -l "v1" --type toml sdk-libs program-libs | while read f; do
echo -e "\n--- $f ---"
rg -B 2 -A 2 "^\s*v1\s*=" "$f"
doneRepository: Lightprotocol/light-protocol
Length of output: 3669
🏁 Script executed:
#!/bin/bash
# Search for light-compressed-token-sdk location
echo "=== Finding light-compressed-token-sdk ==="
find . -name "light-compressed-token-sdk" -type d 2>/dev/null | head -5
echo -e "\n=== Search all Cargo.toml for compressed-token-sdk references ==="
rg "light-compressed-token-sdk" --type toml sdk-libs program-libs -A 1 -B 1Repository: Lightprotocol/light-protocol
Length of output: 2546
🏁 Script executed:
#!/bin/bash
# Check feature propagation patterns in light-sdk and related crates
echo "=== light-sdk Cargo.toml feature block ==="
rg -A 20 "^\[features\]" sdk-libs/light-sdk/Cargo.toml 2>/dev/null || echo "Not found in sdk-libs/light-sdk"
echo -e "\n=== light-token-types Cargo.toml ==="
find sdk-libs -name "light-token-types" -o -name "token-types" | while read d; do
[ -f "$d/Cargo.toml" ] && cat "$d/Cargo.toml" | head -40
done
echo -e "\n=== light-token-interface (program-libs) ==="
find program-libs -name "*token-interface*" -type d | while read d; do
[ -f "$d/Cargo.toml" ] && cat "$d/Cargo.toml" | head -50
doneRepository: Lightprotocol/light-protocol
Length of output: 2782
🏁 Script executed:
#!/bin/bash
# Search for any documentation about v1 vs v2 in codebase
echo "=== Looking for v1/v2 documentation ==="
find . -name "README.md" -o -name "CLAUDE.md" | xargs grep -l "v1\|v2\|layout\|account" 2>/dev/null | head -10 | while read f; do
echo -e "\n--- $f ---"
grep -i -E "v1|v2|layout|account.*v" "$f" | head -5
done
echo -e "\n=== Check if compressed-token-sdk v1 feature is used anywhere ==="
rg "compressed-token-sdk.*v1" --type toml sdk-libs program-libsRepository: Lightprotocol/light-protocol
Length of output: 4784
Remove the incomplete v1 feature stub or implement it fully across the token stack.
The v1 feature in token-sdk/Cargo.toml maps to light-compressed-token-sdk/v1, but that feature is defined as empty (v1 = []). Since light-token-types and light-token-interface have no v1 feature definitions, you cannot actually switch account layouts by enabling v1. Additionally, light-sdk and light-sdk-types are hard-pinned to ["v2"] in dependencies, making any hypothetical v1 functionality moot.
Either remove the v1 feature declaration and its propagation to unclutter the public API, or if V1 account layout support is needed, implement it by:
- Adding
v1 = []tolight-token-typesandlight-token-interface - Having
token-sdk'sv1propagate to these crates - Reviewing whether
light-sdkshould also be version-switchable (currently locked to v2)
🤖 Prompt for AI Agents
In `@sdk-libs/token-sdk/Cargo.toml` around lines 11 - 16, The Cargo feature "v1"
in token-sdk is a dangling stub that references light-compressed-token-sdk/v1
but has no implementation in downstream crates; either remove the v1 feature and
its propagation from token-sdk/Cargo.toml to avoid exposing a non-functional
public API, or implement full v1 support by adding a v1 feature to
light-token-types and light-token-interface (e.g., v1 = []), updating
token-sdk's v1 to propagate to those crates (and to
light-compressed-token-sdk/v1), and then audit light-sdk and light-sdk-types
(currently pinned to ["v2"]) to decide if they should be made version-switchable
or left pinned to v2.
|
|
||
| [dependencies] | ||
| # Light Protocol dependencies | ||
| light-compressed-token-sdk = { workspace = true } |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
# Check the actual Cargo.toml file
cat -n sdk-libs/token-sdk/Cargo.toml | head -50Repository: Lightprotocol/light-protocol
Length of output: 2498
🏁 Script executed:
# Search for light-compressed-token-sdk to understand what it is and where it's located
find . -name "Cargo.toml" -type f | xargs grep -l "light-compressed-token-sdk" | head -20Repository: Lightprotocol/light-protocol
Length of output: 551
🏁 Script executed:
# Look for CLAUDE.md files in token-sdk and related areas
find sdk-libs -name "CLAUDE.md" -o -name "README.md" | xargs cat 2>/dev/null | head -200Repository: Lightprotocol/light-protocol
Length of output: 7035
🏁 Script executed:
# Check if light-compressed-token-sdk is a program-lib or sdk-lib
find . -path "*/light-compressed-token-sdk/Cargo.toml" -o -path "*/compressed-token-sdk/Cargo.toml" | head -10Repository: Lightprotocol/light-protocol
Length of output: 114
🏁 Script executed:
# Look for CLAUDE.md or docs in token-sdk
ls -la sdk-libs/token-sdk/ | grep -E "CLAUDE|README"Repository: Lightprotocol/light-protocol
Length of output: 54
🏁 Script executed:
# Check the structure and dependencies of light-compressed-token-sdk
cat -n sdk-libs/compressed-token-sdk/Cargo.toml | head -60Repository: Lightprotocol/light-protocol
Length of output: 2571
🏁 Script executed:
# Look for any CLAUDE.md files in sdk-libs that document SDK dependencies
find sdk-libs -name "CLAUDE.md" -type fRepository: Lightprotocol/light-protocol
Length of output: 174
🏁 Script executed:
# Check what's in light-token-interface (the shared interface crate mentioned in learnings)
cat -n program-libs/token-interface/Cargo.toml | head -50Repository: Lightprotocol/light-protocol
Length of output: 2185
🏁 Script executed:
# Look at the actual imports/usage in token-sdk to understand the relationship
head -100 sdk-libs/token-sdk/src/lib.rsRepository: Lightprotocol/light-protocol
Length of output: 4170
🏁 Script executed:
# Check if there are other SDK-to-SDK dependencies in the codebase
cd sdk-libs && for f in */Cargo.toml; do echo "=== $f ==="; grep -A 20 "\[dependencies\]" "$f" | grep -E "light-.*-sdk|light-.*-client" | grep -v "^--$"; doneRepository: Lightprotocol/light-protocol
Length of output: 705
🏁 Script executed:
# Look for documentation or comments about SDK layering in CLAUDE.md files
find . -name "CLAUDE.md" -type f | xargs grep -l "SDK\|dependencies\|layering" 2>/dev/null | head -10Repository: Lightprotocol/light-protocol
Length of output: 217
🏁 Script executed:
# Check the specific CLAUDE.md files that might document SDK rules
cat program-libs/token-interface/CLAUDE.md 2>/dev/null || echo "No CLAUDE.md in token-interface"Repository: Lightprotocol/light-protocol
Length of output: 103
🏁 Script executed:
# Check if there's any documentation at sdk-libs level about SDK dependencies
ls -la sdk-libs/ | head -30Repository: Lightprotocol/light-protocol
Length of output: 1059
🏁 Script executed:
# Look at what light-token re-exports from light-compressed-token-sdk
grep -n "pub use.*light_compressed_token_sdk\|pub.*from.*light_compressed_token_sdk" sdk-libs/token-sdk/src/*.rs 2>/dev/null || grep -rn "light_compressed_token_sdk::" sdk-libs/token-sdk/src/ | head -20Repository: Lightprotocol/light-protocol
Length of output: 540
🏁 Script executed:
# Check the root CLAUDE.md to see if there's any documentation about SDK dependencies
cat CLAUDE.md | grep -A 20 -B 5 "SDK\|dependencies" | head -80Repository: Lightprotocol/light-protocol
Length of output: 4599
🏁 Script executed:
# Check program tests CLAUDE.md for any notes on SDK-to-SDK dependencies
cat program-tests/CLAUDE.md | head -100Repository: Lightprotocol/light-protocol
Length of output: 2980
🏁 Script executed:
# Verify if light-compressed-token-sdk is correctly located as an SDK lib
ls -la sdk-libs/compressed-token-sdk/src/ | head -20Repository: Lightprotocol/light-protocol
Length of output: 608
SDK layering violation: light-compressed-token-sdk dependency in SDK crate.
Per the repository's documented policy (root CLAUDE.md), SDK libs must depend only on program-libs, light-prover-client, and external crates. The dependency on light-compressed-token-sdk violates this rule. Since light-token re-exports core functionality from it (constants, error types, SPL interface, utilities), either:
- Move the shared logic to a program-lib (e.g., extend
light-token-interface), or - Document an intentional exception to the layering policy.
🤖 Prompt for AI Agents
In `@sdk-libs/token-sdk/Cargo.toml` at line 33, The Cargo.toml currently adds an
SDK-to-SDK dependency on light-compressed-token-sdk which violates the SDK
layering rule; remove that dependency and either (A) move the shared constants,
error types, SPL interface and utilities currently consumed by light-token into
a program-lib (for example extend or add them to light-token-interface) and
update light-token and this crate to depend on the program-lib instead, or (B)
if this dependency is intentional, add an explicit documented exception to the
repository policy (CLAUDE.md) and justify it in this crate's README/Cargo
manifest comments; reference the crate name light-compressed-token-sdk, the
consumer crate light-token, and the program-lib candidate light-token-interface
when making the change.
| use light_compressed_token_sdk::compressed_token::decompress_full::{ | ||
| decompress_full_token_accounts_with_indices, DecompressFullIndices, | ||
| }; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find light_compressed_token_sdk crate location and examine its Cargo.toml
fd -t f "Cargo.toml" | xargs grep -l "name = \"light-compressed-token-sdk\""Repository: Lightprotocol/light-protocol
Length of output: 112
🏁 Script executed:
#!/bin/bash
# Check the token-sdk Cargo.toml to see the dependency declaration
cat -n sdk-libs/token-sdk/Cargo.toml | head -50Repository: Lightprotocol/light-protocol
Length of output: 2498
🏁 Script executed:
#!/bin/bash
# Search for all references to light_compressed_token_sdk in the codebase to understand its structure
rg "light.compressed.token.sdk|light-compressed-token-sdk" --type toml | head -20Repository: Lightprotocol/light-protocol
Length of output: 1420
🏁 Script executed:
#!/bin/bash
# Check CLAUDE.md files for sdk-libs layering policies
fd -t f "CLAUDE.md" | xargs grep -l "sdk-libs" | head -10Repository: Lightprotocol/light-protocol
Length of output: 283
🏁 Script executed:
#!/bin/bash
# Examine the actual dependency structure - check what light-token-interface contains
ls -la sdk-libs/token-interface/ 2>/dev/null || echo "Directory not found"
fd "token-interface" -t d sdk-libs/Repository: Lightprotocol/light-protocol
Length of output: 91
🏁 Script executed:
#!/bin/bash
# Check if decompress_full functions are truly implementation-specific or should be in light-token-interface
rg "decompress_full" sdk-libs/ --type rust | head -20Repository: Lightprotocol/light-protocol
Length of output: 1609
🏁 Script executed:
#!/bin/bash
# Examine light-compressed-token-sdk dependencies to understand its own layering
cat sdk-libs/compressed-token-sdk/Cargo.toml | head -50Repository: Lightprotocol/light-protocol
Length of output: 1881
🏁 Script executed:
#!/bin/bash
# Check the main CLAUDE.md and sdk-libs related CLAUDE.md files for layering policies
cat CLAUDE.md | grep -A 10 -B 2 "sdk-libs"Repository: Lightprotocol/light-protocol
Length of output: 3304
🏁 Script executed:
#!/bin/bash
# Look at sdk-libs specific documentation
cat sdk-libs/macros/CLAUDE.md 2>/dev/null | head -30Repository: Lightprotocol/light-protocol
Length of output: 1231
🏁 Script executed:
#!/bin/bash
# Check if there's documented exception for light-compressed-token-sdk as a "core" library
rg "compressed-token-sdk|layering|architecture" CLAUDE.md --context 3Repository: Lightprotocol/light-protocol
Length of output: 54
🏁 Script executed:
#!/bin/bash
# Check what light-token-interface actually exports
ls -la sdk-libs/ | grep -E "token|interface"Repository: Lightprotocol/light-protocol
Length of output: 327
🏁 Script executed:
#!/bin/bash
# Verify if light-compressed-token-sdk is classified as program-libs or sdk-libs by its location
find . -name "Cargo.toml" -path "*/sdk-libs/*" -o -name "Cargo.toml" -path "*/program-libs/*" | grep -E "(compressed-token|token-interface)" | head -10Repository: Lightprotocol/light-protocol
Length of output: 156
🏁 Script executed:
#!/bin/bash
# Check if there's any exception documented in CLAUDE.md for sdk-libs → sdk-libs dependencies
rg "light-compressed-token-sdk|sdk-libs.*sdk-libs|exception|allow" CLAUDE.md programs/compressed-token/program/CLAUDE.md sdk-libs/macros/CLAUDE.md --context 2Repository: Lightprotocol/light-protocol
Length of output: 54
🏁 Script executed:
#!/bin/bash
# Verify light-token-interface location to understand if it's in program-libs
fd -t f "Cargo.toml" | xargs grep -l "name = \"light-token-interface\""Repository: Lightprotocol/light-protocol
Length of output: 111
🏁 Script executed:
#!/bin/bash
# Check the actual directory structure to confirm locations
find . -maxdepth 3 -type d -name "*token-interface*" -o -type d -name "*compressed-token*" 2>/dev/null | head -20Repository: Lightprotocol/light-protocol
Length of output: 222
🏁 Script executed:
#!/bin/bash
# Check what's exported from light-compressed-token-sdk and whether it's truly SDK-level code
head -100 sdk-libs/compressed-token-sdk/src/lib.rsRepository: Lightprotocol/light-protocol
Length of output: 1383
🏁 Script executed:
#!/bin/bash
# Check if light-token-interface already has similar decompress functions or if this is truly sdk-level
rg "decompress" program-libs/token-interface/src/ --type rust | head -20Repository: Lightprotocol/light-protocol
Length of output: 2965
🏁 Script executed:
#!/bin/bash
# Understand the dependency graph - does light-compressed-token-sdk depend only on program-libs?
cat sdk-libs/compressed-token-sdk/Cargo.toml | grep -A 30 "\[dependencies\]"Repository: Lightprotocol/light-protocol
Length of output: 1167
🏁 Script executed:
#!/bin/bash
# Look at what DecompressFullIndices and decompress_full_token_accounts_with_indices actually are
cat sdk-libs/compressed-token-sdk/src/compressed_token/v2/decompress_full.rs | head -80Repository: Lightprotocol/light-protocol
Length of output: 3585
🏁 Script executed:
#!/bin/bash
# Verify the import in decompress_runtime.rs is indeed from sdk-libs/compressed-token-sdk
cat -n sdk-libs/token-sdk/src/compressible/decompress_runtime.rs | head -30Repository: Lightprotocol/light-protocol
Length of output: 1638
🏁 Script executed:
#!/bin/bash
# Check if any other sdk-libs crates have similar sdk-libs → sdk-libs dependencies
rg "light-.*-sdk" sdk-libs/*/Cargo.toml | grep "dependencies" -A 20 | head -40Repository: Lightprotocol/light-protocol
Length of output: 54
Move DecompressFullIndices and decompress_full_token_accounts_with_indices to program-libs/token-interface/ to fix sdk-libs dependency layering.
light-token-sdk importing from light-compressed-token-sdk violates the architectural policy. SDK libs must depend only on program-libs, light-prover-client, and external crates—not on other sdk-libs. These decompress functions are core data structures needed across the SDK layer and belong in program-libs/token-interface/ alongside other compressed token abstractions, allowing both light-compressed-token-sdk and light-token-sdk to depend on them without creating sdk-libs-to-sdk-libs coupling.
🤖 Prompt for AI Agents
In `@sdk-libs/token-sdk/src/compressible/decompress_runtime.rs` around lines 3 -
5, The import in decompress_runtime.rs pulls DecompressFullIndices and
decompress_full_token_accounts_with_indices from light_compressed_token_sdk
which creates an sdk-libs-to-sdk-libs dependency; move the definitions of
DecompressFullIndices and decompress_full_token_accounts_with_indices into
program-libs/token-interface so both light-compressed-token-sdk and
light-token-sdk can depend on them, then update decompress_runtime.rs to import
these symbols from the new program-libs/token-interface crate (replace the
current use of light_compressed_token_sdk::compressed_token::decompress_full
with the corresponding module path in program-libs/token-interface) and remove
the old cross-sdklib dependency.
67b207c to
a7bc104
Compare
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
sdk-libs/token-sdk/tests/mint_action_cpi_accounts_tests.rs (2)
27-36: Acceptable test helper, but note potential for data race.The
static mut COUNTERpattern works for generating unique keys within individual tests. Since Rust's test harness runs tests in parallel by default, there's technically a data race here. In practice, collisions are unlikely to cause test failures since each test only needs internal uniqueness.If you ever see flaky tests, consider using
AtomicU8instead:♻️ Thread-safe alternative (optional)
+use std::sync::atomic::{AtomicU8, Ordering}; + +static COUNTER: AtomicU8 = AtomicU8::new(0); + fn pubkey_unique() -> [u8; 32] { - static mut COUNTER: u8 = 0; let mut key = [0u8; 32]; - unsafe { - COUNTER = COUNTER.wrapping_add(1); - key[0] = COUNTER; - } + key[0] = COUNTER.fetch_add(1, Ordering::Relaxed); key }
504-505: Duplicate assertion — appears to be a copy-paste artifact.This
assert!(result.is_err());is repeated twice. The same pattern occurs in several other test functions (lines 571-572, 643-644, 715-716, 781-782, 862-863).🧹 Remove duplicate assertions
let result = MintActionCpiAccounts::<AccountInfo>::try_from_account_infos(&accounts); assert!(result.is_err()); - assert!(result.is_err()); }Apply the same fix to the other affected tests.
🤖 Fix all issues with AI agents
In `@sdk-libs/compressed-token-sdk/Cargo.toml`:
- Around line 9-16: The feature "v1" in Cargo.toml is currently an empty/no-op
feature (v1 = []); confirm intended behavior and either wire it to toggle the
appropriate feature flags (e.g., map "v1" to the legacy layout or API features
used elsewhere) or remove it and add a clear comment documenting it as a
compatibility placeholder; locate the "v1" entry alongside other features like
"anchor-discriminator", "anchor", and "idl-build" and update Cargo.toml
accordingly to either reference the intended dependency features or add a
comment explaining that v1 is intentionally a no-op for compatibility.
- Around line 31-38: This introduces an SDK layering violation by making
light-sdk and light-sdk-types depend directly on each other (see light-sdk and
light-sdk-types in the Cargo.toml diff) — either confirm+document this exception
or move the shared types into a program-lib; specifically, if the dependency is
intentional, add a clear comment/README entry explaining the exception and
rationale where light-sdk and light-sdk-types are defined, otherwise migrate the
shared type definitions from light-sdk-types into a program-lib (e.g., alongside
light-token-interface) so SDKs can depend on program-libs only and update the
Cargo.toml to remove the SDK->SDK dependency.
In `@sdk-libs/compressed-token-sdk/src/utils.rs`:
- Around line 3-5: The code imports LIGHT_TOKEN_PROGRAM_ID from light_sdk_types
but the project should use its own source of truth; replace any import/usage of
light_sdk_types::LIGHT_TOKEN_PROGRAM_ID with
crate::constants::LIGHT_TOKEN_PROGRAM_ID (or
light_sdk::constants::LIGHT_TOKEN_PROGRAM_ID if that is the crate path used
elsewhere) so that all references (the use statement and any places referring to
LIGHT_TOKEN_PROGRAM_ID) reference the local constant instead of light_sdk_types.
In `@sdk-libs/program-test/Cargo.toml`:
- Line 24: The Cargo.toml entry adding light-compressed-token-sdk to
light-program-test violates the layering rule; remove the direct dependency on
light-compressed-token-sdk from the light-program-test Cargo.toml and instead
import the shared types from the program-libs package: move the needed types
into the light-token-interface crate (under program-libs), update their public
API there, then change light-program-test to depend on program-libs (or
light-token-interface) and update all uses/imports to reference the moved types;
ensure any tests or code referencing symbols from light-compressed-token-sdk
(e.g., token type names) are updated to the new module paths and run cargo
build/tests to verify no remaining cross-SDK imports.
In `@sdk-libs/program-test/src/forester/compress_and_close_forester.rs`:
- Line 5: The current use statement imports CompressAndCloseAccounts from
another SDK crate
(light_compressed_token_sdk::compressed_token::CompressAndCloseAccounts), which
creates an SDK-to-SDK dependency; move the CompressAndCloseAccounts type into a
shared program-lib (e.g., light-token-interface or light-compressed-account) and
update consumers to import from that program-lib instead of
light_compressed_token_sdk. Specifically, define the struct in the chosen
program-lib crate, export it from a clear module, then replace the existing use
line in compress_and_close_forester.rs to import the type from the new
program-lib module (and update any paths/names to match the new location).
In `@sdk-libs/token-sdk/src/constants.rs`:
- Around line 25-44: Add unit tests that assert the hard-coded PDAs
COMPRESSIBLE_CONFIG_V1 and RENT_SPONSOR_V1 match the PDAs derived by
CompressibleConfig::light_token_v1_config_pda() and
CompressibleConfig::light_token_v1_rent_sponsor_pda() respectively; implement
these tests in the crate's tests module (or #[cfg(test)] mod) so they run in CI,
failing if the constants drift from the derived values, and include similar
coverage for compression_authority_pda() vs
CompressibleConfig::light_token_v1_compression_authority_pda() to fully lock the
three PDAs.
In `@sdk-libs/token-sdk/src/instruction/mod.rs`:
- Around line 200-203: The implementation of Default for SystemAccounts pulls
TokenDefaultAccounts from light_compressed_token_sdk, causing an SDK-libs
layering breach; fix by removing that dependency: either move
TokenDefaultAccounts into an allowed crate (e.g., program-libs/shared) and
import it there, or re-implement the needed default values inside
token-sdk::instruction::SystemAccounts (or a token-sdk-local
TokenDefaultAccounts) so token-sdk no longer imports light_compressed_token_sdk;
if you intend to keep the cross-crate dependency, add an explicit documented
exception and update the dependency guideline docs accordingly. Ensure
references to SystemAccounts and TokenDefaultAccounts are updated to the chosen
location so the Default impl compiles without importing
light_compressed_token_sdk.
♻️ Duplicate comments (20)
sdk-libs/client/src/interface/create_accounts_proof.rs (1)
4-6: SDK layering violation: sdk-libs shouldn’t depend on another sdk-libs crate.
Importingderive_mint_compressed_addressfromlight_compressed_token_sdk(Line 5) introduces an sdk-libs → sdk-libs dependency. Move this helper into a program-lib (e.g.,light-token-interface) or explicitly document an exception iflight-compressed-token-sdkis meant to be a new layering tier. As per coding guidelines, sdk-libs must depend on program-libs, light-prover-client, and external crates only.sdk-libs/token-client/src/instructions/update_compressed_mint.rs (1)
6-8: SDK layering violation: sdk-libs → sdk-libs dependency.
Line 6 imports fromlight_compressed_token_sdk, which is another sdk-libs crate. Please move the shared API into a program-lib (e.g.,light-token-interface) or document an explicit exception if this new crate is intended to sit below all SDKs. As per coding guidelines, sdk-libs must depend on program-libs, light-prover-client, and external crates only.sdk-libs/token-sdk/src/instruction/create_mints.rs (1)
14-17: SDK layering violation remains for MintActionMetaConfig types.
Line 14–17 still import MintAction meta config types fromlight_compressed_token_sdk, which is another sdk-libs crate. These types should live inlight-token-interface(program-lib) or an approved lower-level crate, or the policy should explicitly allow this new dependency tier. As per coding guidelines, sdk-libs must depend on program-libs, light-prover-client, and external crates only.sdk-libs/token-sdk/src/instruction/decompress_mint.rs (1)
1-5: SDK layering violation: MintActionMetaConfig import.
Line 4 pullsMintActionMetaConfigfromlight_compressed_token_sdk, which breaks the sdk-libs dependency rule. Please move this type to a program-lib (e.g.,light-token-interface) or document an explicit exception for the new SDK layer. As per coding guidelines, sdk-libs must depend on program-libs, light-prover-client, and external crates only.sdk-libs/compressed-token-sdk/src/compat.rs (1)
115-123: Don’t silently coerce unknown account states.
This still defaults invalid state bytes toInitialized, masking corrupted data. Prefer a fallible conversion that returnsProgramError::InvalidAccountData.sdk-libs/compressed-token-sdk/src/spl_interface.rs (1)
55-123: Potential panic onexisting_spl_interface_pda.unwrap()with public fields.
Since the struct is publicly constructible, a caller can setindex > 0without providingexisting_spl_interface_pda, leading to a panic. Consider making fields private with safe constructors, or return aResultfrominstruction()and validate the invariant.sdk-libs/token-client/src/actions/mint_action.rs (1)
5-7: Route compressed‑mint helpers through program‑libs, not another SDK.Directly importing
light_compressed_token_sdkin sdk‑libs source violates the dependency boundary; use a program‑libs wrapper/re‑export instead. As per coding guidelines, ...sdk-libs/token-client/Cargo.toml (1)
17-17: SDK‑to‑SDK dependency breaks sdk‑libs policy.
light-token-clientshould not depend on another SDK crate; move shared utilities into a program‑libs crate (e.g.,light-token-interface) and depend on that instead. Based on learnings, ...sdk-libs/token-sdk/src/instruction/transfer_from_spl.rs (1)
2-7: Dependency layering concern already flagged.This import from
light_compressed_token_sdk(another sdk-lib) intolight-token-sdkhas been identified in a previous review as potentially violating the sdk-libs dependency constraints. As per coding guidelines, sdk-libs should depend only on program-libs, light-prover-client, and external crates.sdk-libs/token-sdk/src/instruction/transfer_to_spl.rs (1)
2-7: Same dependency layering concern astransfer_from_spl.rs.This file exhibits the identical pattern—importing
transfer2types fromlight_compressed_token_sdk(an sdk-lib) intolight-token-sdk(another sdk-lib). The architectural concern raised fortransfer_from_spl.rsapplies equally here. As per coding guidelines, sdk-libs should only depend on program-libs, light-prover-client, and external crates.sdk-libs/program-test/src/compressible.rs (1)
392-392: Consistent with the dependency layering concern in token-sdk.This import pulls
MintActionMetaConfigfromlight_compressed_token_sdkintolight-program-test, which is another sdk-lib. If the team decides to restructure dependencies per the coding guidelines (moving shared types to a program-lib), this import path would need updating accordingly.sdk-libs/client/src/interface/load_accounts.rs (1)
6-11: Same dependency layering pattern as token-sdk modules.The
light-clientcrate (an sdk-lib) now importstransfer2types fromlight_compressed_token_sdk(another sdk-lib). This follows the same architectural pattern flagged in the token-sdk files. If shared types are relocated to a program-lib to satisfy the dependency constraints, this import path would need corresponding updates.sdk-libs/token-sdk/src/instruction/create_mint.rs (1)
4-4: Same dependency layering pattern forMintActionMetaConfig.This import from
light_compressed_token_sdkintolight-token-sdkfollows the same pattern discussed in other files. The concern about sdk-libs depending on other sdk-libs applies here as well.sdk-libs/token-client/src/instructions/mint_to_compressed.rs (1)
6-14: Import paths correctly updated to use the new SDK surface.The migration from
light_token::compressed_tokentolight_compressed_token_sdk::compressed_tokenaligns with the PR's refactoring goals. TheSplInterfacePdais now properly imported at the top level, addressing the previous nitpick.Note: The sdk-lib → sdk-lib dependency boundary concern was previously flagged and remains relevant for architectural documentation.
sdk-libs/token-sdk/src/instruction/transfer_interface.rs (1)
1-1: Avoid sdk-libs → sdk-libs dependency for ownership helper.
light-token-sdknow depends onlight-compressed-token-sdkviais_light_token_owner, which violates the sdk-libs layering rule. Please move/shared this helper into a program-libs crate (e.g.,program-libs/token-interface) or keep a local helper in each SDK to preserve dependency direction. As per coding guidelines, sdk-libs must only depend on program-libs, light-prover-client, and external crates.sdk-libs/token-sdk/src/compressible/decompress_runtime.rs (1)
3-5: SDK layering violation remains at import boundary.Pulling
DecompressFullIndicesanddecompress_full_token_accounts_with_indicesfrom another sdk-libs crate keeps the forbidden dependency direction. Consider relocating these shared primitives into a program-libs crate so both SDKs can depend on it. As per coding guidelines, sdk-libs must only depend on program-libs, light-prover-client, and external crates.sdk-libs/token-sdk/src/spl_interface.rs (1)
6-7: Re-export introduces forbidden sdk-libs coupling.
pub use light_compressed_token_sdk::spl_interface::*makeslight-token-sdkdepend on another sdk-libs crate. Please move shared SPL interface types/utilities into a program-libs crate (e.g.,program-libs/token-interface) and re-export from both SDKs. As per coding guidelines, sdk-libs must only depend on program-libs, light-prover-client, and external crates.sdk-libs/token-sdk/Cargo.toml (2)
9-16:v1feature still appears to be a no-op.
It only enableslight-compressed-token-sdk/v1, which is empty; consider wiring it through or documenting it as a compatibility placeholder.
31-34: SDK-to-SDK dependency still conflicts with the layering policy.
Line 33 adds a dependency onlight-compressed-token-sdk; if SDKs must only depend on program-libs/external crates, please document the exception or relocate shared types to a program-lib. As per coding guidelines, SDK-libs must depend on program-libs, light-prover-client and external crates only.sdk-libs/compressed-token-sdk/src/utils.rs (1)
79-105: Prefer an explicit System Program ID overPubkey::default().
Using a named constant makes intent clearer and avoids relying on implicit all-zero semantics.♻️ Suggested tweak
-use solana_pubkey::Pubkey; +use solana_pubkey::{pubkey, Pubkey}; + +const SYSTEM_PROGRAM_ID: Pubkey = pubkey!("11111111111111111111111111111111"); ... - system_program: Pubkey::default(), + system_program: SYSTEM_PROGRAM_ID,
| [features] | ||
| default = ["anchor-discriminator"] | ||
| v1 = [] | ||
| anchor-discriminator = ["light-sdk/anchor-discriminator"] | ||
| anchor = ["anchor-lang", "light-token-types/anchor", "light-token-interface/anchor"] | ||
| # idl-build feature enables IDL generation for client-side tooling and SDK generation | ||
| idl-build = ["anchor", "anchor-lang/idl-build", "light-sdk/idl-build"] | ||
| cpi-context = ["light-sdk/cpi-context"] |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Confirm whether v1 is intended to be a no-op feature.
Line 11 defines v1 = [], which doesn’t toggle any dependency features; if it should switch layouts/APIs, wire it through or document it as a compatibility placeholder.
🤖 Prompt for AI Agents
In `@sdk-libs/compressed-token-sdk/Cargo.toml` around lines 9 - 16, The feature
"v1" in Cargo.toml is currently an empty/no-op feature (v1 = []); confirm
intended behavior and either wire it to toggle the appropriate feature flags
(e.g., map "v1" to the legacy layout or API features used elsewhere) or remove
it and add a clear comment documenting it as a compatibility placeholder; locate
the "v1" entry alongside other features like "anchor-discriminator", "anchor",
and "idl-build" and update Cargo.toml accordingly to either reference the
intended dependency features or add a comment explaining that v1 is
intentionally a no-op for compatibility.
| light-token-types = { workspace = true } | ||
| light-compressed-account = { workspace = true, features = ["std", "solana"] } | ||
| light-token-interface = { workspace = true } | ||
| light-sdk = { workspace = true, features = ["v2"] } | ||
| light-sdk-types = { workspace = true, features = ["v2"] } | ||
| light-account-checks = { workspace = true, features = ["solana"] } | ||
| light-zero-copy = { workspace = true } | ||
| light-program-profiler = { workspace = true } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find where light-sdk and light-sdk-types are located in the repo
fd -t f "Cargo.toml" | xargs grep -l 'name = "light-sdk"' | head -5Repository: Lightprotocol/light-protocol
Length of output: 95
🏁 Script executed:
# Also check the structure of the repo to understand layering
git ls-files | grep -E "(sdk-libs|program-libs)" | head -20Repository: Lightprotocol/light-protocol
Length of output: 1067
🏁 Script executed:
# Check the CLAUDE.md files mentioned in learnings
find . -name "CLAUDE.md" -type f | head -10Repository: Lightprotocol/light-protocol
Length of output: 452
🏁 Script executed:
# Find light-sdk-types location
fd -t f "Cargo.toml" | xargs grep -l 'name = "light-sdk-types"'Repository: Lightprotocol/light-protocol
Length of output: 101
🏁 Script executed:
# Read the main CLAUDE.md to understand SDK dependency policies
cat ./CLAUDE.mdRepository: Lightprotocol/light-protocol
Length of output: 11426
🏁 Script executed:
# Check the sdk-libs/sdk/Cargo.toml to see what light-sdk depends on
cat sdk-libs/sdk/Cargo.tomlRepository: Lightprotocol/light-protocol
Length of output: 2627
🏁 Script executed:
# Check if there are CLAUDE.md files in sdk-libs
find sdk-libs -name "CLAUDE.md" -type fRepository: Lightprotocol/light-protocol
Length of output: 174
🏁 Script executed:
# Check light-sdk-types Cargo.toml dependencies
cat sdk-libs/sdk-types/Cargo.tomlRepository: Lightprotocol/light-protocol
Length of output: 1116
🏁 Script executed:
# Check what compressed-token-sdk is and its structure
head -50 sdk-libs/compressed-token-sdk/Cargo.tomlRepository: Lightprotocol/light-protocol
Length of output: 1881
Confirm SDK layering violation: light-sdk and light-sdk-types are SDK-lib dependencies, which violates the policy requiring SDK-libs to depend on program-libs, light-prover-client, and external crates only.
Lines 34–35 introduce SDK-to-SDK dependencies. Per the documented policy and the learning that "data structures must be isolated in program-libs (like light-token-interface) so SDKs can import types without pulling in program dependencies," either confirm this exception is intentional and document it, or migrate light-sdk-types to program-libs/ where shared SDK types belong.
🤖 Prompt for AI Agents
In `@sdk-libs/compressed-token-sdk/Cargo.toml` around lines 31 - 38, This
introduces an SDK layering violation by making light-sdk and light-sdk-types
depend directly on each other (see light-sdk and light-sdk-types in the
Cargo.toml diff) — either confirm+document this exception or move the shared
types into a program-lib; specifically, if the dependency is intentional, add a
clear comment/README entry explaining the exception and rationale where
light-sdk and light-sdk-types are defined, otherwise migrate the shared type
definitions from light-sdk-types into a program-lib (e.g., alongside
light-token-interface) so SDKs can depend on program-libs only and update the
Cargo.toml to remove the SDK->SDK dependency.
| use light_sdk::constants::REGISTERED_PROGRAM_PDA; | ||
| use light_sdk_types::LIGHT_TOKEN_PROGRAM_ID; | ||
| use light_token_interface::{ |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Prefer this crate’s LIGHT_TOKEN_PROGRAM_ID constant as the source of truth.
Using crate::constants::LIGHT_TOKEN_PROGRAM_ID avoids potential drift if light_sdk_types changes.
♻️ Suggested tweak
-use light_sdk_types::LIGHT_TOKEN_PROGRAM_ID;
+use crate::constants::LIGHT_TOKEN_PROGRAM_ID;🤖 Prompt for AI Agents
In `@sdk-libs/compressed-token-sdk/src/utils.rs` around lines 3 - 5, The code
imports LIGHT_TOKEN_PROGRAM_ID from light_sdk_types but the project should use
its own source of truth; replace any import/usage of
light_sdk_types::LIGHT_TOKEN_PROGRAM_ID with
crate::constants::LIGHT_TOKEN_PROGRAM_ID (or
light_sdk::constants::LIGHT_TOKEN_PROGRAM_ID if that is the crate path used
elsewhere) so that all references (the use statement and any places referring to
LIGHT_TOKEN_PROGRAM_ID) reference the local constant instead of light_sdk_types.
| light-token-interface = { workspace = true } | ||
| light-compressible = { workspace = true } | ||
| light-token = { workspace = true } | ||
| light-compressed-token-sdk = { workspace = true } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find the crates mentioned in the review
fd -t d "program-test|light-compressed-token-sdk" --full-path "*sdk-libs*"Repository: Lightprotocol/light-protocol
Length of output: 169
🏁 Script executed:
# Check the structure under sdk-libs
ls -la sdk-libs/ 2>/dev/null | head -20Repository: Lightprotocol/light-protocol
Length of output: 1118
🏁 Script executed:
# Read the Cargo.toml file in question
cat -n sdk-libs/program-test/Cargo.tomlRepository: Lightprotocol/light-protocol
Length of output: 3387
🏁 Script executed:
# Check if light-compressed-token-sdk exists and where
fd "light-compressed-token-sdk" -t dRepository: Lightprotocol/light-protocol
Length of output: 54
🏁 Script executed:
# Verify the overall directory structure
tree -L 2 sdk-libs/ 2>/dev/null | head -50Repository: Lightprotocol/light-protocol
Length of output: 868
🏁 Script executed:
# Check if compressed-token-sdk in sdk-libs is the light-compressed-token-sdk
cat sdk-libs/compressed-token-sdk/Cargo.toml | head -5Repository: Lightprotocol/light-protocol
Length of output: 246
🏁 Script executed:
# Look for where light-compressed-token-sdk might be defined (check workspace)
cat Cargo.toml | grep -A 5 "light-compressed-token-sdk"Repository: Lightprotocol/light-protocol
Length of output: 410
🏁 Script executed:
# Check what light-program-test actually imports from light-compressed-token-sdk
rg "light.compressed.token.sdk|from.*compressed.*token.*sdk" sdk-libs/program-test/src/ -A 2Repository: Lightprotocol/light-protocol
Length of output: 809
🏁 Script executed:
# Verify the structure - is light-token-interface in program-libs?
fd "light-token-interface" -t dRepository: Lightprotocol/light-protocol
Length of output: 54
🏁 Script executed:
# Check the CLAUDE.md constraints
cat CLAUDE.md 2>/dev/null | grep -A 10 "SDK-libs"Repository: Lightprotocol/light-protocol
Length of output: 54
🏁 Script executed:
# Check what's in program-libs
ls -la program-libs/ 2>/dev/null | head -20Repository: Lightprotocol/light-protocol
Length of output: 1269
🏁 Script executed:
# Check what light-compressed-token-sdk exports and its dependencies
cat sdk-libs/compressed-token-sdk/Cargo.tomlRepository: Lightprotocol/light-protocol
Length of output: 2266
🏁 Script executed:
# Check light-token-interface location and purpose
cat program-libs/token-interface/Cargo.toml | head -30Repository: Lightprotocol/light-protocol
Length of output: 1085
🏁 Script executed:
# Verify if CompressAndCloseAccounts or MintActionMetaConfig types exist in light-token-interface
rg "CompressAndCloseAccounts|MintActionMetaConfig" program-libs/token-interface/src/ -lRepository: Lightprotocol/light-protocol
Length of output: 54
🏁 Script executed:
# Check the purpose and context of light-program-test - is it a test utility?
cat sdk-libs/program-test/Cargo.toml | grep -A 5 "^\[lib\]\|^\[description\]"Repository: Lightprotocol/light-protocol
Length of output: 54
🏁 Script executed:
# Look at CLAUDE.md rules about program-libs and sdk-libs more carefully
cat CLAUDE.md | grep -B 5 -A 15 "SDK-libs must depend"Repository: Lightprotocol/light-protocol
Length of output: 54
🏁 Script executed:
# Check if light-compressed-token-sdk is documented as an exception or special case
cat sdk-libs/compressed-token-sdk/Cargo.toml -A 20 | head -40Repository: Lightprotocol/light-protocol
Length of output: 1619
🏁 Script executed:
# Check what types/modules are actually used from light-compressed-token-sdk
rg "light_compressed_token_sdk::" sdk-libs/program-test/src/ | cut -d: -f2 | sort -uRepository: Lightprotocol/light-protocol
Length of output: 137
🏁 Script executed:
# Check if those types exist in light-token-interface
rg "struct|enum" program-libs/token-interface/src/ | grep -i "mint\|compress" | head -20Repository: Lightprotocol/light-protocol
Length of output: 2127
🏁 Script executed:
# Read the README for light-program-test to understand its role
cat sdk-libs/program-test/README.md 2>/dev/null || echo "No README found"Repository: Lightprotocol/light-protocol
Length of output: 87
🏁 Script executed:
# Check CLAUDE.md more carefully for full context on SDK-libs rules
head -100 CLAUDE.mdRepository: Lightprotocol/light-protocol
Length of output: 5665
🏁 Script executed:
# See if there are any other SDK-to-SDK dependencies in sdk-libs crates
rg "light-(token|client|event|sdk|compressed)" sdk-libs/*/Cargo.toml | grep -v "workspace = true" | grep -v "optional = true" | grep -v "#"Repository: Lightprotocol/light-protocol
Length of output: 4595
SDK-to-SDK dependencies violate the architecture boundary.
light-program-test in sdk-libs must depend only on program-libs, light-prover-client, and external crates. The direct dependency on light-compressed-token-sdk (another sdk-libs crate) breaches this rule.
Move the required types to light-token-interface (program-libs) so light-program-test can import them from the program-libs layer instead.
🤖 Prompt for AI Agents
In `@sdk-libs/program-test/Cargo.toml` at line 24, The Cargo.toml entry adding
light-compressed-token-sdk to light-program-test violates the layering rule;
remove the direct dependency on light-compressed-token-sdk from the
light-program-test Cargo.toml and instead import the shared types from the
program-libs package: move the needed types into the light-token-interface crate
(under program-libs), update their public API there, then change
light-program-test to depend on program-libs (or light-token-interface) and
update all uses/imports to reference the moved types; ensure any tests or code
referencing symbols from light-compressed-token-sdk (e.g., token type names) are
updated to the new module paths and run cargo build/tests to verify no remaining
cross-SDK imports.
| indexer::Indexer, | ||
| rpc::{Rpc, RpcError}, | ||
| }; | ||
| use light_compressed_token_sdk::compressed_token::CompressAndCloseAccounts as CTokenCompressAndCloseAccounts; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's find and examine the Cargo.toml for sdk-libs/program-test
find sdk-libs/program-test -name "Cargo.toml" -type fRepository: Lightprotocol/light-protocol
Length of output: 104
🏁 Script executed:
# Let's also check the file in question
cat -n sdk-libs/program-test/src/forester/compress_and_close_forester.rs | head -20Repository: Lightprotocol/light-protocol
Length of output: 816
🏁 Script executed:
# Search for light_compressed_token_sdk definition to understand its nature
find . -name "light_compressed_token_sdk" -o -name "*compressed_token_sdk*" | grep -v target | head -20Repository: Lightprotocol/light-protocol
Length of output: 54
🏁 Script executed:
# Check if light_compressed_token_sdk is in program-libs or sdk-libs
fd "Cargo.toml" | xargs grep -l "name = \"light_compressed_token_sdk\"" | head -5Repository: Lightprotocol/light-protocol
Length of output: 54
🏁 Script executed:
cat sdk-libs/program-test/Cargo.tomlRepository: Lightprotocol/light-protocol
Length of output: 2904
🏁 Script executed:
# Search more broadly for compressed_token related crates
rg "name = \"light_compressed_token" --type tomlRepository: Lightprotocol/light-protocol
Length of output: 148
🏁 Script executed:
# Check if it's in sdk-libs or program-libs
fd "Cargo.toml" sdk-libs sdk-libs program-libs | xargs grep -l "light_compressed_token"Repository: Lightprotocol/light-protocol
Length of output: 56
🏁 Script executed:
# Search for light-compressed-token-sdk crate definition
find . -name "Cargo.toml" -type f ! -path "*/target/*" | xargs grep -l "^name = \"light-compressed-token-sdk\"" | head -5Repository: Lightprotocol/light-protocol
Length of output: 114
🏁 Script executed:
# Also search with different naming patterns
find . -name "Cargo.toml" -type f ! -path "*/target/*" | xargs grep -l "light.compressed.token.sdk" | head -10Repository: Lightprotocol/light-protocol
Length of output: 447
🏁 Script executed:
# Check directory structure
ls -la sdk-libs/ | grep -i compress
ls -la program-libs/ | grep -i compressRepository: Lightprotocol/light-protocol
Length of output: 274
🏁 Script executed:
cat sdk-libs/compressed-token-sdk/Cargo.tomlRepository: Lightprotocol/light-protocol
Length of output: 2266
🏁 Script executed:
# Check what CompressAndCloseAccounts is and where it comes from
rg "struct CompressAndCloseAccounts|type CompressAndCloseAccounts" sdk-libs/compressed-token-sdk/src/ -A 3Repository: Lightprotocol/light-protocol
Length of output: 527
SDK‑to‑SDK import violates sdk‑libs boundary.
light_compressed_token_sdk is itself an sdk-lib crate. SDK libraries must depend only on program-libs, light-prover-client, and external crates. Types like CompressAndCloseAccounts should be defined in a program-libs crate (such as light-token-interface or light-compressed-account) so both SDK libraries can import from the shared program-lib layer without creating SDK-to-SDK dependencies. Move the struct to the appropriate program-lib and update the import accordingly.
🤖 Prompt for AI Agents
In `@sdk-libs/program-test/src/forester/compress_and_close_forester.rs` at line 5,
The current use statement imports CompressAndCloseAccounts from another SDK
crate (light_compressed_token_sdk::compressed_token::CompressAndCloseAccounts),
which creates an SDK-to-SDK dependency; move the CompressAndCloseAccounts type
into a shared program-lib (e.g., light-token-interface or
light-compressed-account) and update consumers to import from that program-lib
instead of light_compressed_token_sdk. Specifically, define the struct in the
chosen program-lib crate, export it from a clear module, then replace the
existing use line in compress_and_close_forester.rs to import the type from the
new program-lib module (and update any paths/names to match the new location).
| /// Default compressible config PDA (V1) | ||
| pub const COMPRESSIBLE_CONFIG_V1: Pubkey = pubkey!("ACXg8a7VaqecBWrSbdu73W4Pg9gsqXJ3EXAqkHyhvVXg"); | ||
|
|
||
| /// Default rent sponsor PDA (V1) | ||
| pub const RENT_SPONSOR_V1: Pubkey = pubkey!("r18WwUxfG8kQ69bQPAB2jV6zGNKy3GosFGctjQoV4ti"); | ||
|
|
||
| /// Returns the default compressible config PDA. | ||
| pub fn config_pda() -> Pubkey { | ||
| CompressibleConfig::light_token_v1_config_pda() | ||
| } | ||
|
|
||
| /// Returns the default rent sponsor PDA. | ||
| pub fn rent_sponsor_pda() -> Pubkey { | ||
| CompressibleConfig::light_token_v1_rent_sponsor_pda() | ||
| } | ||
|
|
||
| /// Returns the compression authority PDA. | ||
| pub fn compression_authority_pda() -> Pubkey { | ||
| CompressibleConfig::light_token_v1_compression_authority_pda() | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Guard against drift between hard-coded PDAs and derived PDAs.
Line 26 and Line 29 hard-code PDAs while Line 32/37 derive them via CompressibleConfig; a small test helps ensure they never diverge.
✅ Suggested test to lock PDA constants
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn pda_constants_match_derivations() {
+ assert_eq!(COMPRESSIBLE_CONFIG_V1, CompressibleConfig::light_token_v1_config_pda());
+ assert_eq!(RENT_SPONSOR_V1, CompressibleConfig::light_token_v1_rent_sponsor_pda());
+ }
+}🤖 Prompt for AI Agents
In `@sdk-libs/token-sdk/src/constants.rs` around lines 25 - 44, Add unit tests
that assert the hard-coded PDAs COMPRESSIBLE_CONFIG_V1 and RENT_SPONSOR_V1 match
the PDAs derived by CompressibleConfig::light_token_v1_config_pda() and
CompressibleConfig::light_token_v1_rent_sponsor_pda() respectively; implement
these tests in the crate's tests module (or #[cfg(test)] mod) so they run in CI,
failing if the constants drift from the derived values, and include similar
coverage for compression_authority_pda() vs
CompressibleConfig::light_token_v1_compression_authority_pda() to fully lock the
three PDAs.
| impl Default for SystemAccounts { | ||
| fn default() -> Self { | ||
| use crate::utils::TokenDefaultAccounts; | ||
| use light_compressed_token_sdk::utils::TokenDefaultAccounts; | ||
| let defaults = TokenDefaultAccounts::default(); |
There was a problem hiding this comment.
SDK-libs dependency layering breach.
token-sdk now depends on light_compressed_token_sdk via TokenDefaultAccounts, which conflicts with the guideline that SDK-libs should depend only on program-libs, light-prover-client, or external crates. Please either move TokenDefaultAccounts to an allowed crate (e.g., program-libs/shared), or document an explicit exception and update the guideline.
As per coding guidelines, ensure SDK-libs dependency direction stays compliant.
🤖 Prompt for AI Agents
In `@sdk-libs/token-sdk/src/instruction/mod.rs` around lines 200 - 203, The
implementation of Default for SystemAccounts pulls TokenDefaultAccounts from
light_compressed_token_sdk, causing an SDK-libs layering breach; fix by removing
that dependency: either move TokenDefaultAccounts into an allowed crate (e.g.,
program-libs/shared) and import it there, or re-implement the needed default
values inside token-sdk::instruction::SystemAccounts (or a token-sdk-local
TokenDefaultAccounts) so token-sdk no longer imports light_compressed_token_sdk;
if you intend to keep the cross-crate dependency, add an explicit documented
exception and update the dependency guideline docs accordingly. Ensure
references to SystemAccounts and TokenDefaultAccounts are updated to the chosen
location so the Default impl compiles without importing
light_compressed_token_sdk.
The cpi-context feature was missing from light-compressed-token-sdk, causing the DecompressFullAccounts implementation to not pass the cpi_context to SystemAccountMetaConfig. This resulted in test_decompress_full_cpi_with_context failing with error 20001 (AccountOwnedByWrongProgram).
a7bc104 to
07d0794
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
sdk-libs/token-sdk/src/instruction/decompress_mint.rs (1)
198-215: Fix the account order documentation—mint_signer is not included for decompress operations.The comment on lines 172-187 incorrectly documents position 2 as "mint_signer (no sign for decompress)". For decompress,
MintActionMetaConfig::new()setsmint_signer: None, soto_account_metas()skips it entirely. The actual first account in the list should beauthorityat position 2. Update the comment to accurately reflect the decompress-specific account order, or add a note explaining that mint_signer is conditional and omitted here.sdk-libs/token-sdk/src/instruction/create_mint.rs (1)
1-21: Remove sdk-lib cross-dependency: move shared types to a program-lib.SDK-libs must only depend on program-libs, light-prover-client, and external crates.
light-tokencurrently imports fromlight-compressed-token-sdk(both are sdk-libs), which violates this boundary. MoveMintActionMetaConfigand related types to a program-lib likelight-token-interfaceso both sdk-libs can import them without creating cross-dependencies.
🤖 Fix all issues with AI agents
In `@sdk-libs/compressed-token-sdk/src/spl_interface.rs`:
- Around line 97-132: The AccountMeta entries for the system program in the
instruction() method use Pubkey::default() which is incorrect; replace those
with the actual System Program ID constant (11111111111111111111111111111111) by
adding a SYSTEM_PROGRAM_ID constant and using Pubkey::from(SYSTEM_PROGRAM_ID)
(or the equivalent Sysvar/const) in both the CreateTokenPool and AddTokenPool
branches where AccountMeta::new_readonly(Pubkey::default(), false) currently
appears (within instruction()) so the system program account is correct when
building the Instruction.
In `@sdk-libs/token-client/src/actions/transfer2/spl_to_ctoken.rs`:
- Around line 5-8: This file introduces a forbidden SDK‑to‑SDK dependency by
importing SPL_TOKEN_PROGRAM_ID and find_spl_interface_pda from
light_compressed_token_sdk; remove that direct import and instead consume those
SPL interface helpers from the program‑lib layer (or from a program‑lib
reexport). Update the use statements in spl_to_ctoken.rs to import
SPL_TOKEN_PROGRAM_ID and find_spl_interface_pda from the program‑lib
crate/module that re-exports them (and keep using TransferFromSpl from
light_token), and if needed move or re-export the helper functions/constants
into program‑lib so sdk‑libs no longer depend on another sdk‑lib.
In `@sdk-libs/token-client/src/instructions/update_compressed_mint.rs`:
- Around line 6-8: The current import of
light_compressed_token_sdk::compressed_token::update_compressed_mint (symbols
update_compressed_mint and UpdateMintInputs) violates sdk‑libs layering; move
the shared instruction helpers (the update_compressed_mint function and the
UpdateMintInputs type) into the program‑lib (for example light-token-interface)
or add an approved re‑export in that program‑lib, then update this file to
import update_compressed_mint and UpdateMintInputs from the program‑lib crate
instead of light_compressed_token_sdk to restore proper layering.
♻️ Duplicate comments (19)
sdk-libs/compressed-token-sdk/Cargo.toml (1)
34-35: SDK layering violation:light-sdkandlight-sdk-typesare sdk-lib dependencies.Per the coding guidelines, SDK-libs must depend on program-libs, light-prover-client, and external crates only. Both
light-sdkandlight-sdk-typesreside insdk-libs/, creating an SDK-to-SDK dependency chain. This propagates to all crates that depend onlight-compressed-token-sdk.Either document this as an intentional exception with clear rationale, or migrate the shared types/utilities that
light-compressed-token-sdkneeds from these crates intoprogram-libs/(e.g.,light-token-interface).sdk-libs/program-test/Cargo.toml (1)
24-24: SDK-to-SDK dependency violates the layering policy.
light-program-test(sdk-lib) depending onlight-compressed-token-sdk(sdk-lib) breaches the architecture rule. Either move the required types toprogram-libs/or document this as an intentional exception.sdk-libs/token-client/Cargo.toml (1)
17-17: SDK-to-SDK dependency violates the layering policy.
light-token-client(sdk-lib) depending onlight-compressed-token-sdk(sdk-lib) breaches the architecture rule. The required types and utilities should live inprogram-libs/light-token-interfacewhere both SDKs can depend on them without creating sdk-libs-to-sdk-libs coupling.sdk-libs/token-sdk/src/compressible/decompress_runtime.rs (1)
3-5: SDK-to-SDK import violates layering policy.
light-token-sdk(sdk-lib) importing fromlight-compressed-token-sdk(sdk-lib) creates an sdk-libs-to-sdk-libs dependency. Per the architecture policy,DecompressFullIndicesanddecompress_full_token_accounts_with_indicesshould be moved toprogram-libs/light-token-interfaceso both SDKs can depend on them without cross-SDK coupling.sdk-libs/token-sdk/Cargo.toml (2)
11-11: Thev1feature remains a stub mapping to an empty feature.Looking at the PR context,
light-compressed-token-sdk/v1is defined asv1 = [](empty). This means enablingv1onlight-tokenhas no effect. Either remove this feature declaration to avoid exposing a non-functional API, or implement V1 layout support across the token stack if needed.
31-33: SDK-to-SDK dependency is intentional for this refactor.Per coding guidelines, SDK-libs should depend on program-libs and external crates. However, this PR explicitly extracts
light-compressed-token-sdkas a lower-level SDK fromlight-token-sdk. The dependency direction (token-sdk→compressed-token-sdk) establishes a clear layering wherelight-tokenis the higher-level facade. This architectural decision should be documented in a CLAUDE.md or README for clarity.sdk-libs/token-sdk/src/constants.rs (1)
25-44: Consider adding a test to guard against drift between constants and derived PDAs.The hard-coded
COMPRESSIBLE_CONFIG_V1andRENT_SPONSOR_V1constants should always match their derived counterparts. A simple unit test would catch any future divergence:✅ Suggested test
#[cfg(test)] mod tests { use super::*; #[test] fn pda_constants_match_derivations() { assert_eq!(COMPRESSIBLE_CONFIG_V1, config_pda()); assert_eq!(RENT_SPONSOR_V1, rent_sponsor_pda()); } }sdk-libs/compressed-token-sdk/src/spl_interface.rs (1)
55-62: Public fields allow bypassing constructor invariants, risking a panic.The struct has public fields, allowing consumers to construct it manually with
index > 0butexisting_spl_interface_pda = None. This causes anunwrap()panic at line 123. Consider making fields private or usingexpect()with a descriptive message.sdk-libs/token-client/src/actions/mint_action.rs (1)
5-7: SDK‑to‑SDK dependency still breaches sdk‑libs boundary.This is the same dependency‑layering concern previously raised for this file; sdk‑libs should not depend on other sdk‑libs. Please route via a program‑lib re‑export or document an approved exception. As per coding guidelines, ...
sdk-libs/program-test/src/forester/compress_and_close_forester.rs (1)
5-5: SDK‑to‑SDK dependency still breaches sdk‑libs boundary.Same issue previously raised: sdk‑libs should not depend on other sdk‑libs. Route via a program‑lib type or re‑export. As per coding guidelines, ...
sdk-libs/token-sdk/src/instruction/transfer_from_spl.rs (1)
2-7: SDK‑to‑SDK dependency still breaches sdk‑libs boundary.This repeats the earlier dependency‑layering concern. Move these shared transfer2 types into a program‑lib interface and import from there. As per coding guidelines, ...
sdk-libs/token-sdk/src/instruction/create_mints.rs (1)
14-17: Dependency policy concern already flagged.This import from
light_compressed_token_sdk(another sdk-lib crate) was previously identified as potentially violating the sdk-libs dependency policy. Per the coding guidelines, sdk-libs should depend only on program-libs, light-prover-client, and external crates.However, given the PR's stated objective is to extract
light-compressed-token-sdkand havelight-token-sdkdepend on and re-export from it, this appears to be an intentional architectural decision. If this layering is approved, consider documenting this exception in CLAUDE.md or the crate's README.sdk-libs/token-sdk/src/instruction/transfer_to_spl.rs (1)
1-7: Duplicate: sdk-lib dependency boundary concern.Same issue as noted in
sdk-libs/token-sdk/src/instruction/create_mint.rs. As per coding guidelines, ...sdk-libs/token-client/src/instructions/mint_to_compressed.rs (1)
6-14: Duplicate: sdk-lib dependency boundary concern.This matches the prior review feedback on sdk-lib → sdk-lib dependencies for this file.
Also applies to: 69-69
sdk-libs/token-sdk/src/instruction/transfer_interface.rs (1)
1-10: Duplicate: sdk-lib dependency boundary concern.Same dependency-boundary issue as noted earlier for sdk-libs. As per coding guidelines, ...
sdk-libs/token-sdk/src/instruction/mod.rs (1)
200-203: SDK-libs dependency layering still applies here.
Defaulting throughTokenDefaultAccountsfromlight_compressed_token_sdkpreserves the sdk-libs → sdk-libs dependency concern; consider relocating defaults or documenting an exception. As per coding guidelines, SDK-libs should depend only on program-libs/external crates.#!/bin/bash # Confirm usage sites and dependency entry points rg -n "TokenDefaultAccounts" sdk-libs/token-sdk/src -g '*.rs' rg -n "light-compressed-token-sdk|light_compressed_token_sdk" sdk-libs/token-sdk/Cargo.tomlsdk-libs/compressed-token-sdk/src/compat.rs (2)
115-123: Avoid defaulting unknown state toInitialized.
A fallible conversion prevents silently treating corrupted state bytes as initialized.#!/bin/bash # Find conversions from light_token_interface::state::TokenData rg -n "light_token_interface::state::TokenData" -g '*.rs' rg -n "TokenData::from\\(" -g '*.rs'
83-94: Use a discriminator-specific error instead ofEmptyInput.
ReturningEmptyInputwhen a discriminator is present but unsupported obscures the root cause; a dedicated error variant would be clearer.#!/bin/bash # Locate HasherError definition and current variants rg -n "enum HasherError" -g '*.rs' rg -n "HasherError::" -g '*.rs' sdk-libssdk-libs/compressed-token-sdk/src/utils.rs (1)
3-16: Avoid sdk‑libs → sdk‑libs dependencies here.
light_sdk::constants::REGISTERED_PROGRAM_PDAandlight_sdk_types::LIGHT_TOKEN_PROGRAM_IDare SDK‑libs; the guideline requires sdk‑libs to depend only on program‑libs/external crates. Please move/re‑export these constants into this crate or a program‑lib and import from there. As per coding guidelines, ...
- light-token-sdk now depends on and re-exports modules from light-compressed-token-sdk
- Removed low-level compressed token code from light-token-sdk
- TokenSdkError moved to light-compressed-token-sdk (covers errors 17001-17033)
- New LightTokenError in light-token-sdk for high-level token operations (errors 17500-17510)
- light-token-sdk re-exports TokenSdkError from light-compressed-token-sdk
Summary by CodeRabbit
New Features
Refactor
Chores
✏️ Tip: You can customize this high-level summary in your review settings.