Skip to content

fix: sdk macros#2190

Merged
ananas-block merged 3 commits intomainfrom
jorrit/fix-macros
Jan 21, 2026
Merged

fix: sdk macros#2190
ananas-block merged 3 commits intomainfrom
jorrit/fix-macros

Conversation

@ananas-block
Copy link
Contributor

@ananas-block ananas-block commented Jan 20, 2026

Summary by CodeRabbit

  • New Features

    • Support for mint-only programs (no PDA accounts), including a MintOnly instruction variant and placeholder account scaffolding.
  • Bug Fixes

    • Explicit error handling for empty token/account variants in decompress paths.
  • Chores / Refactor

    • Tests gated behind a "test-only" feature flag.
    • Simplified decompression generation and seed-provider handling to better accommodate programs without PDA seeds.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 20, 2026

📝 Walkthrough

Walkthrough

Adds mint-only codegen support to the light_pdas macros (placeholder enums, trait stubs, and branching for mint-only flows) and gates two test files behind a test-only feature flag.

Changes

Cohort / File(s) Summary
Test Configuration
program-libs/token-interface/tests/token/spl_compat.rs, program-libs/token-interface/tests/token/zero_copy_new.rs
Add #![cfg(feature = "test-only")] crate-level attributes to conditionally compile/run tests only when the test-only feature is enabled.
Mint-only decompress handling
sdk-libs/macros/src/light_pdas/account/decompress_context.rs
Insert explicit Empty match arm for mint-only (no PDA ctx seeds) that returns InvalidAccountData, added to both pda collection and LightAccountVariant handling paths.
Token account placeholders & utils
sdk-libs/macros/src/light_pdas/account/utils.rs
Replace prior empty enum with TokenAccountVariant and PackedTokenAccountVariant (both Empty), add Anchor serialize/deserialize, Pack/Unpack impls, TokenSeedProvider impl returning InvalidAccountData, and an IntoCTokenVariant fallback that panics if used.
Decompress builder / seed providers
sdk-libs/macros/src/light_pdas/program/decompress.rs
Remove account_types field/parameter from DecompressBuilder::new; make generate_seed_provider_impls fast-path return Ok(Vec::new()) when no PDA seeds (mint-only/token-only) and produce clearer error when variants exist but seeds missing.
Instruction codegen & mint-only scaffolding
sdk-libs/macros/src/light_pdas/program/instructions.rs
Add has_mint_fields flag to codegen, propagate has_any_mint_fields from wrapper, branch to emit mint-only placeholder LightAccountVariant and trait stubs when no PDA seeds, add MintOnly decision in instruction selection, and update DecompressBuilder call site (removed arg).
Instruction parsing enum
sdk-libs/macros/src/light_pdas/program/parsing.rs
Add public MintOnly variant to InstructionVariant enum.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

ai-review

Suggested reviewers

  • sergeytimoshin
  • SwenSchaeferjohann

Poem

🌱 No PDA, no panic — a mint-only way,
Empty variants stand in, steady as day.
Traits stitched neatly, seeds gently shorn,
Tests wait behind flags till the feature is born. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'fix: sdk macros' is vague and generic, failing to specify which macros were fixed or what the actual fixes address. Provide a more specific title that indicates the primary change, such as 'fix: add mint-only program support to sdk macros' or 'fix: handle empty PDA variants in decompress context'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 70.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jorrit/fix-macros

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@sdk-libs/macros/src/light_pdas/account/utils.rs`:
- Around line 151-156: The impl of IntoCTokenVariant for TokenAccountVariant
uses unreachable!() in into_ctoken_variant which can panic; change it to return
the safe fallback LightAccountVariant::Empty instead. Locate the method
TokenAccountVariant::into_ctoken_variant (impl
light_sdk::interface::IntoCTokenVariant<LightAccountVariant,
light_token::compat::TokenData> for TokenAccountVariant) and replace the
unreachable!() call with a deterministic return of LightAccountVariant::Empty so
it matches the defensive behavior of Pack/Unpack/TokenSeedProvider.

In `@sdk-libs/macros/src/light_pdas/program/decompress.rs`:
- Around line 158-165: The current generate_seed_provider_impls function
silently returns Ok(Vec::new()) when self.pda_seeds is None or empty, which can
hide a mismatch if self.pda_ctx_seeds contains variants; update the guard to
detect this mismatch and fail fast: if pda_seeds is None/empty but pda_ctx_seeds
is non-empty, return an Err with a clear message referencing the program and the
missing PDA seed specs; otherwise, when pda_seeds exists and is non-empty,
proceed as before. Ensure the error message mentions
generate_seed_provider_impls, pda_seeds, and pda_ctx_seeds so it's easy to
locate and debug.

Comment on lines +151 to +156
impl light_sdk::interface::IntoCTokenVariant<LightAccountVariant, light_token::compat::TokenData> for TokenAccountVariant {
fn into_ctoken_variant(self, _token_data: light_token::compat::TokenData) -> LightAccountVariant {
// This function should never be called for programs without token accounts.
// The Empty variant only exists in mint-only programs (no PDAs).
// For programs with PDAs but no tokens, this impl exists only to satisfy trait bounds.
unreachable!("into_ctoken_variant called on program without token accounts")
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's explore the file structure and find the file in question
cd /repo && find . -name "utils.rs" | grep -E "macros/.*light_pdas.*account"

Repository: Lightprotocol/light-protocol

Length of output: 127


🏁 Script executed:

# Read the specific file to see the context around lines 151-156
wc -l sdk-libs/macros/src/light_pdas/account/utils.rs

Repository: Lightprotocol/light-protocol

Length of output: 123


🏁 Script executed:

# Read the file with context
cat -n sdk-libs/macros/src/light_pdas/account/utils.rs | head -200 | tail -80

Repository: Lightprotocol/light-protocol

Length of output: 4068


🏁 Script executed:

# Search for the IntoCTokenVariant trait definition
rg "trait IntoCTokenVariant" --type rs -A 10

Repository: Lightprotocol/light-protocol

Length of output: 98


🏁 Script executed:

# Search for usages of TokenAccountVariant and into_ctoken_variant
rg "TokenAccountVariant" --type rs -B 2 -A 2

Repository: Lightprotocol/light-protocol

Length of output: 98


🏁 Script executed:

# Search for other unreachable! patterns in similar macros code
rg "unreachable!" sdk-libs/macros --type rs -B 2 -A 2

Repository: Lightprotocol/light-protocol

Length of output: 98


🏁 Script executed:

# Check for LightAccountVariant::Empty definition and usage
rg "LightAccountVariant::Empty" --type rs -B 2 -A 2

Repository: Lightprotocol/light-protocol

Length of output: 98


🏁 Script executed:

rg "trait IntoCTokenVariant" --type-list

Repository: Lightprotocol/light-protocol

Length of output: 461


🏁 Script executed:

rg "trait IntoCTokenVariant" -A 10

Repository: Lightprotocol/light-protocol

Length of output: 805


🏁 Script executed:

rg "into_ctoken_variant" -B 3 -A 3

Repository: Lightprotocol/light-protocol

Length of output: 4496


🏁 Script executed:

rg "TokenAccountVariant" -B 2 -A 2 | head -100

Repository: Lightprotocol/light-protocol

Length of output: 8886


🏁 Script executed:

# Look at how other generated Empty enums handle trait implementations
rg "generate_empty_ctoken_enum" -B 5 -A 20

Repository: Lightprotocol/light-protocol

Length of output: 5140


🏁 Script executed:

# Check if there are other unreachable! macros in the generated code sections
rg "unreachable!" sdk-libs/macros -B 3 -A 1

Repository: Lightprotocol/light-protocol

Length of output: 1516


🏁 Script executed:

rg "enum LightAccountVariant" -A 15

Repository: Lightprotocol/light-protocol

Length of output: 3172


🏁 Script executed:

# Check how this Empty TokenAccountVariant is used/called
rg "into_ctoken_variant" --context 5

Repository: Lightprotocol/light-protocol

Length of output: 5900


🏁 Script executed:

# See if there are defensive patterns (returning a default/empty variant) elsewhere
rg "LightAccountVariant::" sdk-libs/sdk -A 1 | head -50

Repository: Lightprotocol/light-protocol

Length of output: 54


🏁 Script executed:

# Check the trait documentation more carefully
cat -n sdk-libs/sdk/src/interface/traits.rs | grep -A 20 "trait IntoCTokenVariant"

Repository: Lightprotocol/light-protocol

Length of output: 505


🏁 Script executed:

# Search for where into_ctoken_variant is invoked
rg "\.into_ctoken_variant\(" -B 5 -A 3

Repository: Lightprotocol/light-protocol

Length of output: 54


🏁 Script executed:

# Search for calls that might guard against the empty case
rg "into_ctoken_variant" -B 10 | head -80

Repository: Lightprotocol/light-protocol

Length of output: 6725


🏁 Script executed:

# Check if there's any match/guard logic before calling
rg "match.*TokenAccountVariant" -A 5 | head -60

Repository: Lightprotocol/light-protocol

Length of output: 54


Replace unreachable!() with safe fallback to LightAccountVariant::Empty.

The into_ctoken_variant implementation for the empty token variant currently uses unreachable!(), which will panic on-chain if ever invoked. While the intent is that this path should never execute, the other trait impls on TokenAccountVariant::Empty (Pack, Unpack, TokenSeedProvider) all use defensive returns. For consistency and safety, return LightAccountVariant::Empty:

Suggested fix
-                unreachable!("into_ctoken_variant called on program without token accounts")
+                LightAccountVariant::Empty
🤖 Prompt for AI Agents
In `@sdk-libs/macros/src/light_pdas/account/utils.rs` around lines 151 - 156, The
impl of IntoCTokenVariant for TokenAccountVariant uses unreachable!() in
into_ctoken_variant which can panic; change it to return the safe fallback
LightAccountVariant::Empty instead. Locate the method
TokenAccountVariant::into_ctoken_variant (impl
light_sdk::interface::IntoCTokenVariant<LightAccountVariant,
light_token::compat::TokenData> for TokenAccountVariant) and replace the
unreachable!() call with a deterministic return of LightAccountVariant::Empty so
it matches the defensive behavior of Pack/Unpack/TokenSeedProvider.

@ananas-block ananas-block merged commit 6acc776 into main Jan 21, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants