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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
72 changes: 72 additions & 0 deletions Cargo.lock

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

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@ members = [
"sdk-tests/csdk-anchor-full-derived-test-sdk",
"sdk-tests/single-mint-test",
"sdk-tests/single-pda-test",
"sdk-tests/single-account-loader-test",
"sdk-tests/single-ata-test",
"sdk-tests/single-token-test",
"sdk-tests/manual-test",
"forester-utils",
"forester",
"sparse-merkle-tree",
Expand Down Expand Up @@ -142,7 +144,7 @@ litesvm = "0.7"
# Anchor
anchor-lang = { version = "0.31.1" }
anchor-spl = { version = "0.31.1" }
light-anchor-spl = { version = "0.31.1", features = ["idl-build", "memo"] }
light-anchor-spl = { version = "0.31.1", features = ["memo"] }

# Anchor compatibility
borsh = { version = "0.10.4", default-features = false }
Expand Down
5 changes: 3 additions & 2 deletions forester/src/compressible/pda/compressor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::sync::{
use borsh::BorshDeserialize;
use forester_utils::rpc_pool::SolanaRpcPool;
use futures::StreamExt;
use light_account_checks::discriminator::DISCRIMINATOR_LEN;
use light_client::{
indexer::Indexer,
interface::instructions::{
Expand Down Expand Up @@ -91,8 +92,8 @@ impl<R: Rpc + Indexer> PdaCompressor<R> {
anyhow::anyhow!("Config account not found for program {}", program_id)
})?;

// LightConfig is stored with raw Borsh serialization (no Anchor discriminator)
let config = LightConfig::try_from_slice(&config_account.data)
// LightConfig has 8-byte discriminator prefix, skip it for deserialization
let config = LightConfig::try_from_slice(&config_account.data[DISCRIMINATOR_LEN..])
.map_err(|e| anyhow::anyhow!("Failed to deserialize config: {:?}", e))?;

// Validate config at startup to fail fast on misconfigurations
Expand Down
4 changes: 2 additions & 2 deletions forester/src/compressible/pda/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ use crate::{
Result,
};

/// Layout: [8-byte discriminator][Option<CompressionInfo>][rest of data]
/// Layout: [8-byte discriminator][CompressionInfo][rest of data]
fn extract_compression_info(data: &[u8]) -> Option<CompressionInfo> {
const DISCRIMINATOR_SIZE: usize = 8;
if data.len() <= DISCRIMINATOR_SIZE {
return None;
}
Option::<CompressionInfo>::deserialize(&mut &data[DISCRIMINATOR_SIZE..]).ok()?
CompressionInfo::deserialize(&mut &data[DISCRIMINATOR_SIZE..]).ok()
}

fn calculate_compressible_slot(
Expand Down
11 changes: 8 additions & 3 deletions forester/tests/test_compressible_pda.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ const CSDK_TEST_PROGRAM_ID: &str = "FAMipfVEhN4hjCLpKCvjDXXfzLsoVTqQccXzePz1L1ah
// This needs to match the discriminator from csdk_anchor_full_derived_test::state::d1_field_types::single_pubkey::SinglePubkeyRecord
const SINGLE_PUBKEY_RECORD_DISCRIMINATOR: [u8; 8] = csdk_anchor_full_derived_test::state::d1_field_types::single_pubkey::SinglePubkeyRecord::LIGHT_DISCRIMINATOR;

// Rent sponsor pubkey used in tests
const RENT_SPONSOR: Pubkey = solana_sdk::pubkey!("CLEuMG7pzJX9xAuKCFzBP154uiG1GaNo4Fq7x6KAcAfG");
// Rent sponsor pubkey used in tests - must match the program's rent sponsor PDA
const RENT_SPONSOR: Pubkey =
Pubkey::new_from_array(csdk_anchor_full_derived_test::PROGRAM_RENT_SPONSOR_DATA.0);

/// Context returned from forester registration
struct ForesterContext {
Expand Down Expand Up @@ -332,6 +333,7 @@ async fn test_compressible_pda_bootstrap() {
let accounts = csdk_anchor_full_derived_test::accounts::D8PdaOnly {
fee_payer: authority.pubkey(),
compression_config: config_pda,
pda_rent_sponsor: csdk_anchor_full_derived_test::program_rent_sponsor(),
d8_pda_only_record: record_pda,
system_program: solana_sdk::system_program::ID,
};
Expand Down Expand Up @@ -520,6 +522,7 @@ async fn test_compressible_pda_compression() {
let accounts = csdk_anchor_full_derived_test::accounts::D8PdaOnly {
fee_payer: authority.pubkey(),
compression_config: config_pda,
pda_rent_sponsor: csdk_anchor_full_derived_test::program_rent_sponsor(),
d8_pda_only_record: record_pda,
system_program: solana_sdk::system_program::ID,
};
Expand Down Expand Up @@ -642,7 +645,7 @@ async fn test_compressible_pda_compression() {
let deserialized = SinglePubkeyRecord::try_from_slice(compressed_data)
.expect("Failed to deserialize SinglePubkeyRecord from compressed account");

let compression_info = deserialized.compression_info.clone();
let compression_info = deserialized.compression_info;

let expected_record = SinglePubkeyRecord {
compression_info,
Expand Down Expand Up @@ -781,6 +784,7 @@ async fn test_compressible_pda_subscription() {
let accounts = csdk_anchor_full_derived_test::accounts::D8PdaOnly {
fee_payer: authority.pubkey(),
compression_config: config_pda,
pda_rent_sponsor: csdk_anchor_full_derived_test::program_rent_sponsor(),
d8_pda_only_record: record_pda_1,
system_program: solana_sdk::system_program::ID,
};
Expand Down Expand Up @@ -843,6 +847,7 @@ async fn test_compressible_pda_subscription() {
let accounts_2 = csdk_anchor_full_derived_test::accounts::D8PdaOnly {
fee_payer: authority.pubkey(),
compression_config: config_pda,
pda_rent_sponsor: csdk_anchor_full_derived_test::program_rent_sponsor(),
d8_pda_only_record: record_pda_2,
system_program: solana_sdk::system_program::ID,
};
Expand Down
1 change: 1 addition & 0 deletions program-libs/compressed-account/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ alloc = ["light-hasher/alloc"]
std = ["alloc", "borsh/std", "light-zero-copy/std"]
solana = ["dep:solana-pubkey", "dep:solana-program-error", "solana-msg"]
anchor = ["anchor-lang", "std"]
idl-build = ["anchor-lang/idl-build", "anchor"]
pinocchio = ["dep:pinocchio"]
bytemuck-des = ["bytemuck"]
new-unique = ["dep:solana-pubkey"]
Expand Down
1 change: 1 addition & 0 deletions program-libs/compressible/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ license = "MIT"
default = ["solana"]
solana = ["dep:solana-program-error", "light-compressed-account/solana", "light-account-checks/solana", "solana-sysvar", "solana-msg"]
anchor = ["anchor-lang", "light-compressed-account/anchor", "light-compressed-account/std", "light-account-checks/solana"]
idl-build = ["anchor-lang/idl-build", "anchor", "light-compressed-account/idl-build"]
pinocchio = ["dep:pinocchio", "light-compressed-account/pinocchio", "light-account-checks/pinocchio"]
profile-program = []
profile-heap = ["dep:light-heap"]
Expand Down
2 changes: 2 additions & 0 deletions program-libs/compressible/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,6 @@ pub struct CreateAccountsProof {
/// State merkle tree index (needed for mint creation decompress validation).
/// This is optional to maintain backwards compatibility.
pub state_tree_index: Option<u8>,
/// Offset in remaining_accounts where Light system accounts start.
pub system_accounts_offset: u8,
}
1 change: 1 addition & 0 deletions program-libs/token-interface/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ license = "MIT"

[features]
anchor = ["light-compressed-account/anchor", "dep:anchor-lang", "light-compressible/anchor"]
idl-build = ["anchor-lang/idl-build", "anchor", "light-compressed-account/idl-build", "light-compressible/idl-build"]
solana = ["dep:solana-program-error", "dep:solana-sysvar", "solana-msg"]
default = []
test-only = []
Expand Down
10 changes: 6 additions & 4 deletions program-libs/token-interface/src/state/token/borsh.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use borsh::{BorshDeserialize, BorshSerialize};
use light_compressed_account::Pubkey;

use crate::state::{AccountState, ExtensionStruct, Token, ACCOUNT_TYPE_TOKEN_ACCOUNT};
use crate::{
state::{AccountState, ExtensionStruct, Token, ACCOUNT_TYPE_TOKEN_ACCOUNT},
AnchorDeserialize, AnchorSerialize,
};

// Manual implementation of BorshSerialize for SPL compatibility
impl BorshSerialize for Token {
impl AnchorSerialize for Token {
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
// Write mint (32 bytes)
writer.write_all(&self.mint.to_bytes())?;
Expand Down Expand Up @@ -61,7 +63,7 @@ impl BorshSerialize for Token {
}

// Manual implementation of BorshDeserialize for SPL compatibility
impl BorshDeserialize for Token {
impl AnchorDeserialize for Token {
fn deserialize_reader<R: std::io::Read>(buf: &mut R) -> std::io::Result<Self> {
// Read mint (32 bytes)
let mut mint_bytes = [0u8; 32];
Expand Down
27 changes: 27 additions & 0 deletions program-libs/token-interface/src/state/token/token_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,33 @@ pub struct Token {
pub extensions: Option<Vec<ExtensionStruct>>,
}

// IdlBuild trait impl (provides default implementations)
#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for Token {}

// IDL inherent methods required for UFCS calls from AnchorSerialize derive macro.
// When anchor-lang/idl-build is enabled, the macro generates code like
// `<Token>::get_full_path()`. These calls need inherent methods since the
// IdlBuild trait may not be in scope at the call site.
#[cfg(feature = "idl-build")]
impl Token {
#[doc(hidden)]
pub fn get_full_path() -> String {
std::any::type_name::<Self>().into()
}

#[doc(hidden)]
pub fn create_type() -> Option<anchor_lang::idl::types::IdlTypeDef> {
None
}

#[doc(hidden)]
pub fn insert_types(
_types: &mut std::collections::BTreeMap<String, anchor_lang::idl::types::IdlTypeDef>,
) {
}
}

impl Token {
/// Extract amount directly from account data slice using hardcoded offset
/// Token layout: mint (32 bytes) + owner (32 bytes) + amount (8 bytes)
Expand Down
6 changes: 3 additions & 3 deletions programs/compressed-token/anchor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@ no-log-ix-name = []
cpi = ["no-entrypoint"]
custom-heap = ["light-heap"]
mem-profiling = []
default = ["custom-heap", "idl-build"]
default = ["custom-heap"]
test-sbf = []
bench-sbf = []
cpi-context = []
idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build", "light-token-interface/idl-build"]
cpi-without-program-ids = []

[dependencies]
anchor-lang = { workspace = true }
anchor-spl = { version = "0.31.1", features = ["idl-build"] }
anchor-spl = { version = "0.31.1" }
spl-token = { workspace = true, features = ["no-entrypoint"] }
account-compression = { workspace = true, features = ["cpi", "no-idl"] }
light-system-program-anchor = { workspace = true, features = ["cpi"] }
Expand Down
2 changes: 1 addition & 1 deletion programs/compressed-token/anchor/src/burn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ pub mod sdk {
} else {
spl_token::ID
};
let accounts = crate::accounts::BurnInstruction {
let accounts = crate::__client_accounts_burn_instruction::BurnInstruction {
fee_payer: inputs.fee_payer,
authority: inputs.authority,
cpi_authority_pda,
Expand Down
4 changes: 2 additions & 2 deletions programs/compressed-token/anchor/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ pub mod sdk {
inputs: serialized_ix_data,
};

let accounts = crate::accounts::GenericInstruction {
let accounts = crate::__client_accounts_generic_instruction::GenericInstruction {
fee_payer: inputs.fee_payer,
authority: inputs.authority,
cpi_authority_pda,
Expand Down Expand Up @@ -413,7 +413,7 @@ pub mod sdk {
inputs: serialized_ix_data,
};

let accounts = crate::accounts::GenericInstruction {
let accounts = crate::__client_accounts_generic_instruction::GenericInstruction {
fee_payer: inputs.fee_payer,
authority: inputs.authority,
cpi_authority_pda,
Expand Down
2 changes: 1 addition & 1 deletion programs/compressed-token/anchor/src/freeze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ pub mod sdk {
.data()
};

let accounts = crate::accounts::FreezeInstruction {
let accounts = crate::__client_accounts_freeze_instruction::FreezeInstruction {
fee_payer: inputs.fee_payer,
authority: inputs.authority,
cpi_authority_pda,
Expand Down
12 changes: 0 additions & 12 deletions programs/compressed-token/anchor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,18 +232,6 @@ pub mod light_compressed_token {
) -> Result<()> {
burn::process_burn(ctx, inputs)
}

/// This function is a stub to allow Anchor to include the input types in
/// the IDL. It should not be included in production builds nor be called in
/// practice.
#[cfg(feature = "idl-build")]
pub fn stub_idl_build<'info>(
_ctx: Context<'_, '_, '_, 'info, TransferInstruction<'info>>,
_inputs1: CompressedTokenInstructionDataTransfer,
_inputs2: TokenData,
) -> Result<()> {
Err(ErrorCode::InstructionNotCallable.into())
}
}

#[error_code]
Expand Down
Loading
Loading