refactor: light program pinocchio macro#2247
Conversation
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📝 WalkthroughWalkthroughThis PR introduces a unified backend-driven code generation abstraction for light_pdas macros. It replaces hard-coded per-framework (Anchor vs Pinocchio) generation paths with a Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 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: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
sdk-libs/macros/src/light_pdas/accounts/variant.rs (2)
666-681: 🧹 Nitpick | 🔵 TrivialHard-coded
light_account_pinocchio::solana_pubkey::Pubkey— same leaky-abstraction pattern.Line 670 reaches directly into
light_account_pinocchio::solana_pubkey::Pubkey. This is the third place where pinocchio-specific paths are hard-coded despite having a backend parameter. Consider a backend method likepubkey_from_seed_field(field_expr: TokenStream) -> TokenStreamto encapsulate the conversion.
754-823:⚠️ Potential issue | 🟠 Major
generate_packed_seeds_struct_with_backenduses unqualifiedPubkeytype for pinocchio—creates type mismatch with [u8; 32] seed values.
extract_seed_fieldsat lines 788 and 811 storespacked_field_type: quote! { Pubkey }for DataRooted and FunctionCall pubkey fields. The seeds struct generation correctly applies backend conversion at lines 145–153, mapping all pubkey types to[u8; 32]for pinocchio. However,generate_packed_seeds_struct_with_backendat line 213 usessf.packed_field_typedirectly without any backend check.For pinocchio with DataRooted pubkey seeds: the unpacked struct has
pub field: [u8; 32], but the packed struct would emitpub field: Pubkey(bare, unqualified). Ingenerate_pack_seed_fieldsat line 674, the code tries to assignself.seeds.#field([u8; 32]) directly to the packed field (Pubkey), causing a type mismatch compile error.Apply the same backend-aware conversion to
generate_packed_seeds_struct_with_backendthat is applied togenerate_seeds_struct_with_backend. For pinocchio, map non-account pubkey fields to[u8; 32]in the packed struct, matching the unpacked struct's type.
🤖 Fix all issues with AI agents
In `@sdk-libs/macros/src/light_pdas/accounts/variant.rs`:
- Around line 586-592: The branching on backend.is_pinocchio() inside the
has_le_bytes case is redundant because extract_seed_fields already sets
sf.field_type to u64 for has_le_bytes seeds; remove the special-case branch and
always generate the same arm using sf.field_type (i.e., use `#field`:
`#ty`::from_le_bytes(self.seeds.#field) where ty = &sf.field_type) so the code no
longer implies a backend-specific difference; update the match arm that
currently checks sf.has_le_bytes and references backend.is_pinocchio()
accordingly.
- Around line 162-192: Refactor the repeated backend.is_pinocchio() branching in
generate_seeds_struct_with_backend, generate_packed_seeds_struct_with_backend,
generate_variant_struct_with_backend, and
generate_packed_variant_struct_with_backend by computing an optional doc
attribute once and reusing it in the quote! blocks (or add a doc_attr(&self,
text: &str) -> TokenStream helper on CodegenBackend and call that);
specifically, build let doc_attr = if backend.is_pinocchio() { quote!{} } else {
let doc = format!("Seeds for {} PDA.", self.variant_name); quote! { #[doc =
`#doc`] } } and then include `#doc_attr` in the struct generation quotes to remove
the duplicated if/else branches that only differ by the doc attribute.
- Around line 440-485: Replace the hard-coded account types in the Pack
implementations for `#variant_name` with the backend-provided types: use
backend.account_meta_type() instead of
`#account_crate`::solana_instruction::AccountMeta in the impl header, and use
backend.account_info_type() instead of pinocchio::account_info::AccountInfo and
`#account_crate`::AccountInfo<'static> when calling self.derive_pda::<...>();
update both the pinocchio branch and the generic AM branch so
derive_pda::<...>() and the Pack<AM> signature reference the
backend.account_info_type() / backend.account_meta_type() helpers (ensuring any
required lifetime is applied to account_info_type() where previously 'static was
used).
- Around line 373-389: The backend-specific branch in unpack_data is
unnecessary; replace the if/else on backend.is_pinocchio() with a single unified
block that always constructs ProgramPackedAccounts via
`#account_crate`::packed_accounts::ProgramPackedAccounts and calls <#inner_type as
`#account_crate`::LightAccount>::unpack(&self.data, &packed_accounts). Ensure the
error mapping still returns `#sdk_error`::InvalidInstructionData on unpack failure
and remove the special-case reference to
light_account_pinocchio::light_account_checks::packed_accounts::ProgramPackedAccounts.
In `@sdk-libs/macros/src/light_pdas/program/instructions.rs`:
- Around line 849-866: In process_update_config, the account variables are
reversed: it currently sets authority = &accounts[0] and config = &accounts[1]
but later builds remaining as [*config, *authority] and callers expect config
first (as declared earlier around lines 606-612); fix by swapping the
assignments so config = &accounts[0] and authority = &accounts[1] (so remaining
remains [*config, *authority]) before calling
account_crate::process_update_light_config.
In `@sdk-libs/macros/src/light_pdas/program/variant_enum.rs`:
- Around line 106-133: The generate_light_account_data_struct_with_backend
function hardcodes borsh derives for the non-pinocchio branch; update the
LightAccountData generation to use the backend-provided tokens serialize_derive
and deserialize_derive instead of borsh::BorshSerialize/borsh::BorshDeserialize
so both branches consistently use backend.serialize_derive() and
backend.deserialize_derive(); modify the else branch that builds the
LightAccountData struct to replace the hardcoded derives with `#serialize_derive`
and `#deserialize_derive` (same pattern used in the pinocchio branch).
| if backend.is_pinocchio() { | ||
| quote! { | ||
| #[cfg(not(target_os = "solana"))] | ||
| impl #account_crate::Pack<#account_crate::solana_instruction::AccountMeta> for #variant_name { | ||
| type Packed = #packed_variant_name; | ||
|
|
||
| fn pack( | ||
| &self, | ||
| accounts: &mut #account_crate::PackedAccounts, | ||
| ) -> std::result::Result<Self::Packed, #sdk_error> { | ||
| use #account_crate::LightAccountVariantTrait; | ||
| let (_, bump) = self.derive_pda::<pinocchio::account_info::AccountInfo>(); | ||
| Ok(#packed_variant_name { | ||
| seeds: #packed_seeds_struct_name { | ||
| #(#pack_seed_fields,)* | ||
| bump, | ||
| }, | ||
| data: #pack_data, | ||
| }) | ||
| } | ||
| } | ||
| } | ||
| } else { | ||
| quote! { | ||
| // Pack trait is only available off-chain (client-side packing) | ||
| #[cfg(not(target_os = "solana"))] | ||
| impl<AM: #account_crate::AccountMetaTrait> #account_crate::Pack<AM> for #variant_name { | ||
| type Packed = #packed_variant_name; | ||
|
|
||
| fn pack( | ||
| &self, | ||
| accounts: &mut #account_crate::interface::instruction::PackedAccounts<AM>, | ||
| ) -> std::result::Result<Self::Packed, #sdk_error> { | ||
| use #account_crate::LightAccountVariantTrait; | ||
| let (_, bump) = self.derive_pda::<#account_crate::AccountInfo<'static>>(); | ||
| Ok(#packed_variant_name { | ||
| seeds: #packed_seeds_struct_name { | ||
| #(#pack_seed_fields,)* | ||
| bump, | ||
| }, | ||
| data: #pack_data, | ||
| }) | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find the CodegenBackend trait definition and its methods
fd -t f "backend" sdk-libs/macros --type rust | head -20Repository: Lightprotocol/light-protocol
Length of output: 243
🏁 Script executed:
#!/bin/bash
# Search for CodegenBackend trait definition
rg -n "trait CodegenBackend" --type rust -A 30Repository: Lightprotocol/light-protocol
Length of output: 2839
🏁 Script executed:
#!/bin/bash
# Check for account_info_type or account_meta_type methods
rg -n "fn account_info_type|fn account_meta_type|fn account_info_trait" --type rust -B 2 -A 5Repository: Lightprotocol/light-protocol
Length of output: 4734
🏁 Script executed:
#!/bin/bash
# Read the exact lines 440-485 in variant.rs
sed -n '440,485p' sdk-libs/macros/src/light_pdas/accounts/variant.rs | cat -nRepository: Lightprotocol/light-protocol
Length of output: 2509
🏁 Script executed:
#!/bin/bash
# Look for CLAUDE.md files that might guide macro implementation
find . -name "CLAUDE.md" -o -name "*.md" | grep -i "macro\|account" | head -10Repository: Lightprotocol/light-protocol
Length of output: 569
Use backend.account_info_type() and backend.account_meta_type() instead of hard-coded type paths.
Lines 443, 451, and 464 hard-code type paths that the CodegenBackend trait already provides via account_info_type() and account_meta_type() methods. The backend abstraction exists specifically to centralize SDK-specific type selection—leverage it rather than bypassing it with hard-coded paths.
Apply backend methods for type consistency
Line 443: Replace #account_crate::solana_instruction::AccountMeta with backend.account_meta_type()
Line 451: Replace pinocchio::account_info::AccountInfo with backend.account_info_type()
Line 464: Replace #account_crate::AccountInfo<'static> with backend.account_info_type() (with proper lifetime handling)
🤖 Prompt for AI Agents
In `@sdk-libs/macros/src/light_pdas/accounts/variant.rs` around lines 440 - 485,
Replace the hard-coded account types in the Pack implementations for
`#variant_name` with the backend-provided types: use backend.account_meta_type()
instead of `#account_crate`::solana_instruction::AccountMeta in the impl header,
and use backend.account_info_type() instead of
pinocchio::account_info::AccountInfo and `#account_crate`::AccountInfo<'static>
when calling self.derive_pda::<...>(); update both the pinocchio branch and the
generic AM branch so derive_pda::<...>() and the Pack<AM> signature reference
the backend.account_info_type() / backend.account_meta_type() helpers (ensuring
any required lifetime is applied to account_info_type() where previously 'static
was used).
- Fix account order bug in process_update_config (config=0, authority=1) - Use backend-provided serialize/deserialize derives in LightAccountData - Remove redundant is_pinocchio() branch for has_le_bytes unpack fields - DRY doc attribute generation across 4 struct generation methods - Unify unpack_data path using account_crate re-export for both backends
* refactor: light program pinocchio macro * fix: address CodeRabbit review comments on macro codegen - Fix account order bug in process_update_config (config=0, authority=1) - Use backend-provided serialize/deserialize derives in LightAccountData - Remove redundant is_pinocchio() branch for has_le_bytes unpack fields - DRY doc attribute generation across 4 struct generation methods - Unify unpack_data path using account_crate re-export for both backends
refactor remove fetch-accounts renaming, simplify trait fomat excl photon-api submodule fix: multi-pass cold account lookup in test indexer RPC Align get_account_interface and get_multiple_account_interfaces with Photon's lookup strategy: search compressed_accounts by onchain_pubkey, then by PDA seed derivation, then token_compressed_accounts, then by token_data.owner. Also fix as_mint() to accept ColdContext::Account since Photon returns mints as generic compressed accounts. Co-authored-by: Cursor <cursoragent@cursor.com> lint fix lint fix: reject rent sponsor self-referencing the token account (#2257) * fix: reject rent sponsor self-referencing the token account Audit issue #9 (INFO): The rent payer could be the same account as the target token account being created. Add a check that rejects this self-reference to prevent accounting issues. * test: add failing test rent sponsor self reference fix: process metadata add/remove actions in sequential order (#2256) * fix: process metadata add/remove actions in sequential order Audit issue #16 (LOW): should_add_key checked for any add and any remove independently, ignoring action ordering. An add-remove-add sequence would incorrectly remove the key. Process actions sequentially so the final state reflects the actual order. * chore: format * test: add randomized test for metadata action processing Validates that process_extensions_config_with_actions produces correct AdditionalMetadataConfig for random sequences of UpdateMetadataField and RemoveMetadataKey actions, covering the add-remove-add bug from audit issue #16. * test: add integration test for audit issue #13 (no double rent charge) Verifies that two compress operations targeting the same compressible CToken account in a single Transfer2 instruction do not double-charge the rent top-up budget. * chore: format extensions_metadata test fix: validate authority on self-transfer early return (#2252) * fix: handle self-transfer in ctoken transfer and transfer_checked Validate that the authority is a signer and is the owner or delegate before allowing self-transfer early return. Previously the self-transfer path returned Ok(()) without any authority validation. * fix: simplify map_or to is_some_and per clippy * fix: use pubkey_eq for self-transfer check * refactor: extract self-transfer validation into shared function Extract duplicate self-transfer check from default.rs and checked.rs into validate_self_transfer() in shared.rs with cold path for authority validation. * chore: format * fix: deduplicate random metadata keys in test_random_mint_action Random key generation could produce duplicate keys, causing DuplicateMetadataKey error (18040) with certain seeds. fix: enforce mint extension checks in cToken-to-cToken decompress (#2246) * fix: enforce mint extension checks in cToken-to-cToken decompress hot path Add enforce_extension_state() to MintExtensionChecks and call it in the Decompress branch when decompress_inputs is None (hot-path, not CompressedOnly restore). This prevents cToken-to-cToken transfers from bypassing pause, transfer fee, and transfer hook restrictions. * fix test chore: reject compress for mints with restricted extensions in build_mint_extension_cache (#2240) * chore: reject compress for mints with restricted extensions in mint check * Update programs/compressed-token/program/src/compressed_token/transfer2/check_extensions.rs Co-authored-by: 0xa5df-c <172008956+0xa5df-c@users.noreply.github.com> * fix: format else-if condition for lint --------- Co-authored-by: 0xa5df-c <172008956+0xa5df-c@users.noreply.github.com> fix: token-pool index 0 check (#2239) fix(programs): add MintCloseAuthority as restricted extension (M-03) (#2263) * fix: add MintCloseAuthority as restricted extension (M-03) A mint with MintCloseAuthority can be closed and re-opened with different extensions. Treating it as restricted ensures compressed tokens from such mints require CompressedOnly mode. * test: add MintCloseAuthority compression_only requirement tests Add test coverage for MintCloseAuthority requiring compression_only mode, complementing the fix in f2da063. refactor: light program pinocchio macro (#2247) * refactor: light program pinocchio macro * fix: address CodeRabbit review comments on macro codegen - Fix account order bug in process_update_config (config=0, authority=1) - Use backend-provided serialize/deserialize derives in LightAccountData - Remove redundant is_pinocchio() branch for has_le_bytes unpack fields - DRY doc attribute generation across 4 struct generation methods - Unify unpack_data path using account_crate re-export for both backends chore(libs): bump versions (#2272) fix(programs): allow account-level delegate to compress CToken (M-02) (#2262) * fix: allow account-level delegate to compress tokens from CToken (M-02) check_ctoken_owner() only checked owner and permanent delegate. An account-level delegate (approved via CTokenApprove) could not compress tokens. Added delegate check after permanent delegate. * test: compress by delegate fix: accumulate delegated amount at decompression (#2242) * fix: accumulate delegated amount at decompression * fix lint * refactor: simplify apply_delegate to single accumulation path * fix: ignore delegated_amount without delegate * restore decompress amount check fix programtest, wallet owner tracking for ata fmt and lint
refactor remove fetch-accounts renaming, simplify trait fomat excl photon-api submodule fix: multi-pass cold account lookup in test indexer RPC Align get_account_interface and get_multiple_account_interfaces with Photon's lookup strategy: search compressed_accounts by onchain_pubkey, then by PDA seed derivation, then token_compressed_accounts, then by token_data.owner. Also fix as_mint() to accept ColdContext::Account since Photon returns mints as generic compressed accounts. Co-authored-by: Cursor <cursoragent@cursor.com> lint fix lint fix: reject rent sponsor self-referencing the token account (#2257) * fix: reject rent sponsor self-referencing the token account Audit issue #9 (INFO): The rent payer could be the same account as the target token account being created. Add a check that rejects this self-reference to prevent accounting issues. * test: add failing test rent sponsor self reference fix: process metadata add/remove actions in sequential order (#2256) * fix: process metadata add/remove actions in sequential order Audit issue #16 (LOW): should_add_key checked for any add and any remove independently, ignoring action ordering. An add-remove-add sequence would incorrectly remove the key. Process actions sequentially so the final state reflects the actual order. * chore: format * test: add randomized test for metadata action processing Validates that process_extensions_config_with_actions produces correct AdditionalMetadataConfig for random sequences of UpdateMetadataField and RemoveMetadataKey actions, covering the add-remove-add bug from audit issue #16. * test: add integration test for audit issue #13 (no double rent charge) Verifies that two compress operations targeting the same compressible CToken account in a single Transfer2 instruction do not double-charge the rent top-up budget. * chore: format extensions_metadata test fix: validate authority on self-transfer early return (#2252) * fix: handle self-transfer in ctoken transfer and transfer_checked Validate that the authority is a signer and is the owner or delegate before allowing self-transfer early return. Previously the self-transfer path returned Ok(()) without any authority validation. * fix: simplify map_or to is_some_and per clippy * fix: use pubkey_eq for self-transfer check * refactor: extract self-transfer validation into shared function Extract duplicate self-transfer check from default.rs and checked.rs into validate_self_transfer() in shared.rs with cold path for authority validation. * chore: format * fix: deduplicate random metadata keys in test_random_mint_action Random key generation could produce duplicate keys, causing DuplicateMetadataKey error (18040) with certain seeds. fix: enforce mint extension checks in cToken-to-cToken decompress (#2246) * fix: enforce mint extension checks in cToken-to-cToken decompress hot path Add enforce_extension_state() to MintExtensionChecks and call it in the Decompress branch when decompress_inputs is None (hot-path, not CompressedOnly restore). This prevents cToken-to-cToken transfers from bypassing pause, transfer fee, and transfer hook restrictions. * fix test chore: reject compress for mints with restricted extensions in build_mint_extension_cache (#2240) * chore: reject compress for mints with restricted extensions in mint check * Update programs/compressed-token/program/src/compressed_token/transfer2/check_extensions.rs Co-authored-by: 0xa5df-c <172008956+0xa5df-c@users.noreply.github.com> * fix: format else-if condition for lint --------- Co-authored-by: 0xa5df-c <172008956+0xa5df-c@users.noreply.github.com> fix: token-pool index 0 check (#2239) fix(programs): add MintCloseAuthority as restricted extension (M-03) (#2263) * fix: add MintCloseAuthority as restricted extension (M-03) A mint with MintCloseAuthority can be closed and re-opened with different extensions. Treating it as restricted ensures compressed tokens from such mints require CompressedOnly mode. * test: add MintCloseAuthority compression_only requirement tests Add test coverage for MintCloseAuthority requiring compression_only mode, complementing the fix in f2da063. refactor: light program pinocchio macro (#2247) * refactor: light program pinocchio macro * fix: address CodeRabbit review comments on macro codegen - Fix account order bug in process_update_config (config=0, authority=1) - Use backend-provided serialize/deserialize derives in LightAccountData - Remove redundant is_pinocchio() branch for has_le_bytes unpack fields - DRY doc attribute generation across 4 struct generation methods - Unify unpack_data path using account_crate re-export for both backends chore(libs): bump versions (#2272) fix(programs): allow account-level delegate to compress CToken (M-02) (#2262) * fix: allow account-level delegate to compress tokens from CToken (M-02) check_ctoken_owner() only checked owner and permanent delegate. An account-level delegate (approved via CTokenApprove) could not compress tokens. Added delegate check after permanent delegate. * test: compress by delegate fix: accumulate delegated amount at decompression (#2242) * fix: accumulate delegated amount at decompression * fix lint * refactor: simplify apply_delegate to single accumulation path * fix: ignore delegated_amount without delegate * restore decompress amount check fix programtest, wallet owner tracking for ata fmt and lint
refactor remove fetch-accounts renaming, simplify trait fomat excl photon-api submodule fix: multi-pass cold account lookup in test indexer RPC Align get_account_interface and get_multiple_account_interfaces with Photon's lookup strategy: search compressed_accounts by onchain_pubkey, then by PDA seed derivation, then token_compressed_accounts, then by token_data.owner. Also fix as_mint() to accept ColdContext::Account since Photon returns mints as generic compressed accounts. Co-authored-by: Cursor <cursoragent@cursor.com> lint fix lint fix: reject rent sponsor self-referencing the token account (#2257) * fix: reject rent sponsor self-referencing the token account Audit issue #9 (INFO): The rent payer could be the same account as the target token account being created. Add a check that rejects this self-reference to prevent accounting issues. * test: add failing test rent sponsor self reference fix: process metadata add/remove actions in sequential order (#2256) * fix: process metadata add/remove actions in sequential order Audit issue #16 (LOW): should_add_key checked for any add and any remove independently, ignoring action ordering. An add-remove-add sequence would incorrectly remove the key. Process actions sequentially so the final state reflects the actual order. * chore: format * test: add randomized test for metadata action processing Validates that process_extensions_config_with_actions produces correct AdditionalMetadataConfig for random sequences of UpdateMetadataField and RemoveMetadataKey actions, covering the add-remove-add bug from audit issue #16. * test: add integration test for audit issue #13 (no double rent charge) Verifies that two compress operations targeting the same compressible CToken account in a single Transfer2 instruction do not double-charge the rent top-up budget. * chore: format extensions_metadata test fix: validate authority on self-transfer early return (#2252) * fix: handle self-transfer in ctoken transfer and transfer_checked Validate that the authority is a signer and is the owner or delegate before allowing self-transfer early return. Previously the self-transfer path returned Ok(()) without any authority validation. * fix: simplify map_or to is_some_and per clippy * fix: use pubkey_eq for self-transfer check * refactor: extract self-transfer validation into shared function Extract duplicate self-transfer check from default.rs and checked.rs into validate_self_transfer() in shared.rs with cold path for authority validation. * chore: format * fix: deduplicate random metadata keys in test_random_mint_action Random key generation could produce duplicate keys, causing DuplicateMetadataKey error (18040) with certain seeds. fix: enforce mint extension checks in cToken-to-cToken decompress (#2246) * fix: enforce mint extension checks in cToken-to-cToken decompress hot path Add enforce_extension_state() to MintExtensionChecks and call it in the Decompress branch when decompress_inputs is None (hot-path, not CompressedOnly restore). This prevents cToken-to-cToken transfers from bypassing pause, transfer fee, and transfer hook restrictions. * fix test chore: reject compress for mints with restricted extensions in build_mint_extension_cache (#2240) * chore: reject compress for mints with restricted extensions in mint check * Update programs/compressed-token/program/src/compressed_token/transfer2/check_extensions.rs Co-authored-by: 0xa5df-c <172008956+0xa5df-c@users.noreply.github.com> * fix: format else-if condition for lint --------- Co-authored-by: 0xa5df-c <172008956+0xa5df-c@users.noreply.github.com> fix: token-pool index 0 check (#2239) fix(programs): add MintCloseAuthority as restricted extension (M-03) (#2263) * fix: add MintCloseAuthority as restricted extension (M-03) A mint with MintCloseAuthority can be closed and re-opened with different extensions. Treating it as restricted ensures compressed tokens from such mints require CompressedOnly mode. * test: add MintCloseAuthority compression_only requirement tests Add test coverage for MintCloseAuthority requiring compression_only mode, complementing the fix in f2da063. refactor: light program pinocchio macro (#2247) * refactor: light program pinocchio macro * fix: address CodeRabbit review comments on macro codegen - Fix account order bug in process_update_config (config=0, authority=1) - Use backend-provided serialize/deserialize derives in LightAccountData - Remove redundant is_pinocchio() branch for has_le_bytes unpack fields - DRY doc attribute generation across 4 struct generation methods - Unify unpack_data path using account_crate re-export for both backends chore(libs): bump versions (#2272) fix(programs): allow account-level delegate to compress CToken (M-02) (#2262) * fix: allow account-level delegate to compress tokens from CToken (M-02) check_ctoken_owner() only checked owner and permanent delegate. An account-level delegate (approved via CTokenApprove) could not compress tokens. Added delegate check after permanent delegate. * test: compress by delegate fix: accumulate delegated amount at decompression (#2242) * fix: accumulate delegated amount at decompression * fix lint * refactor: simplify apply_delegate to single accumulation path * fix: ignore delegated_amount without delegate * restore decompress amount check fix programtest, wallet owner tracking for ata fmt and lint upd amm test simplify client usage, remove unnecessary endpoints clean cleanup lint
refactor remove fetch-accounts renaming, simplify trait fomat excl photon-api submodule fix: multi-pass cold account lookup in test indexer RPC Align get_account_interface and get_multiple_account_interfaces with Photon's lookup strategy: search compressed_accounts by onchain_pubkey, then by PDA seed derivation, then token_compressed_accounts, then by token_data.owner. Also fix as_mint() to accept ColdContext::Account since Photon returns mints as generic compressed accounts. Co-authored-by: Cursor <cursoragent@cursor.com> lint fix lint fix: reject rent sponsor self-referencing the token account (#2257) * fix: reject rent sponsor self-referencing the token account Audit issue #9 (INFO): The rent payer could be the same account as the target token account being created. Add a check that rejects this self-reference to prevent accounting issues. * test: add failing test rent sponsor self reference fix: process metadata add/remove actions in sequential order (#2256) * fix: process metadata add/remove actions in sequential order Audit issue #16 (LOW): should_add_key checked for any add and any remove independently, ignoring action ordering. An add-remove-add sequence would incorrectly remove the key. Process actions sequentially so the final state reflects the actual order. * chore: format * test: add randomized test for metadata action processing Validates that process_extensions_config_with_actions produces correct AdditionalMetadataConfig for random sequences of UpdateMetadataField and RemoveMetadataKey actions, covering the add-remove-add bug from audit issue #16. * test: add integration test for audit issue #13 (no double rent charge) Verifies that two compress operations targeting the same compressible CToken account in a single Transfer2 instruction do not double-charge the rent top-up budget. * chore: format extensions_metadata test fix: validate authority on self-transfer early return (#2252) * fix: handle self-transfer in ctoken transfer and transfer_checked Validate that the authority is a signer and is the owner or delegate before allowing self-transfer early return. Previously the self-transfer path returned Ok(()) without any authority validation. * fix: simplify map_or to is_some_and per clippy * fix: use pubkey_eq for self-transfer check * refactor: extract self-transfer validation into shared function Extract duplicate self-transfer check from default.rs and checked.rs into validate_self_transfer() in shared.rs with cold path for authority validation. * chore: format * fix: deduplicate random metadata keys in test_random_mint_action Random key generation could produce duplicate keys, causing DuplicateMetadataKey error (18040) with certain seeds. fix: enforce mint extension checks in cToken-to-cToken decompress (#2246) * fix: enforce mint extension checks in cToken-to-cToken decompress hot path Add enforce_extension_state() to MintExtensionChecks and call it in the Decompress branch when decompress_inputs is None (hot-path, not CompressedOnly restore). This prevents cToken-to-cToken transfers from bypassing pause, transfer fee, and transfer hook restrictions. * fix test chore: reject compress for mints with restricted extensions in build_mint_extension_cache (#2240) * chore: reject compress for mints with restricted extensions in mint check * Update programs/compressed-token/program/src/compressed_token/transfer2/check_extensions.rs Co-authored-by: 0xa5df-c <172008956+0xa5df-c@users.noreply.github.com> * fix: format else-if condition for lint --------- Co-authored-by: 0xa5df-c <172008956+0xa5df-c@users.noreply.github.com> fix: token-pool index 0 check (#2239) fix(programs): add MintCloseAuthority as restricted extension (M-03) (#2263) * fix: add MintCloseAuthority as restricted extension (M-03) A mint with MintCloseAuthority can be closed and re-opened with different extensions. Treating it as restricted ensures compressed tokens from such mints require CompressedOnly mode. * test: add MintCloseAuthority compression_only requirement tests Add test coverage for MintCloseAuthority requiring compression_only mode, complementing the fix in f2da063. refactor: light program pinocchio macro (#2247) * refactor: light program pinocchio macro * fix: address CodeRabbit review comments on macro codegen - Fix account order bug in process_update_config (config=0, authority=1) - Use backend-provided serialize/deserialize derives in LightAccountData - Remove redundant is_pinocchio() branch for has_le_bytes unpack fields - DRY doc attribute generation across 4 struct generation methods - Unify unpack_data path using account_crate re-export for both backends chore(libs): bump versions (#2272) fix(programs): allow account-level delegate to compress CToken (M-02) (#2262) * fix: allow account-level delegate to compress tokens from CToken (M-02) check_ctoken_owner() only checked owner and permanent delegate. An account-level delegate (approved via CTokenApprove) could not compress tokens. Added delegate check after permanent delegate. * test: compress by delegate fix: accumulate delegated amount at decompression (#2242) * fix: accumulate delegated amount at decompression * fix lint * refactor: simplify apply_delegate to single accumulation path * fix: ignore delegated_amount without delegate * restore decompress amount check fix programtest, wallet owner tracking for ata fmt and lint upd amm test simplify client usage, remove unnecessary endpoints clean cleanup lint
abstract framework-specific differences (serialization derives, crate paths, types, error handling).
generate*_with_backend(backend) methods; build() and build_for_pinocchio() now delegate to build_with_backend().
backend-parameterized methods (1451→961 lines).
the CodegenBackend trait (557→520 lines).
_with_backend pattern (838→696 lines).
generate_light_program_items_pinocchio() unified into generate_light_program_items_with_backend() (1424→1213 lines).
Summary by CodeRabbit