Skip to content

refactor: ctoken sdk builder instructions2#2069

Merged
ananas-block merged 7 commits intomainfrom
jorrit/refactor-ctoken-sdk-builder-instructions2
Nov 24, 2025
Merged

refactor: ctoken sdk builder instructions2#2069
ananas-block merged 7 commits intomainfrom
jorrit/refactor-ctoken-sdk-builder-instructions2

Conversation

@ananas-block
Copy link
Contributor

@ananas-block ananas-block commented Nov 22, 2025

Add CToken sdk instructions

  • all have functional test coverage in a native test programsdk-tests/sdk-ctoken-test
    1. close - Close compressed token accounts
    2. compressible - Compressible token parameters and configuration
    3. create - Create compressed token accounts
    4. create_ata - Create Associated Token Account for compressed tokens
    5. create_cmint - Create compressed mint
    6. mint_to - Mint compressed tokens to an account
    7. transfer_ctoken - Transfer compressed tokens (ctoken to ctoken)
    8. transfer_ctoken_spl - Transfer from compressed token to SPL token
    9. transfer_interface - Transfer interface abstraction (with SPL bridge config)
    10. transfer_spl_ctoken - Transfer from SPL token to compressed token

Summary by CodeRabbit

  • New Features

    • Builder-style APIs for creating compressed token accounts, associated token accounts (V1/V2), compressed mints, and mint-to flows; new CPI and account-info helpers.
    • New end-to-end transfer flows between compressed tokens and SPL tokens (both directions).
  • Improvements

    • Consolidated account-meta generation via config objects and clearer builder patterns.
    • Optional compressible parameters and streamlined CPI/write paths.
  • Refactor

    • Removed legacy helper entry points and reorganized public exports for a more ergonomic SDK surface.

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

refactor: transfer ctoken

stash

refactor: compressed-token-sdk

move create token account

stash

stash

feat: ctoken create cmint

fixed compilation issues

feat: add mint to ctoken

stash ctoken test

test_mint_to_ctoken works

test: sdk transfer spl ctokens

test transfer interface

refactor: split up transfer interface rs
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 22, 2025

Walkthrough

Large SDK refactor: replaced many free-function instruction builders with struct-based builders and account-info wrappers, centralized mint-action account-meta generation into MintActionMetaConfig instance API, added new ctoken/ATA/CMint/mint-to/transfer modules, reorganized exports, and applied minor program-side predicate/formatting tweaks.

Changes

Cohort / File(s) Summary
Mint-action meta refactor
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs, sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/mod.rs
Converted MintActionMetaConfig to an instance-based struct (new constructors, cpi_context, builder helpers) and replaced free get_*_account_metas functions with to_account_metas(); adjusted CPI-write semantics (removed mint_needs_to_sign).
Call-site adaptations (mint/create/update)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/{create_compressed_mint,instruction.rs, mint_to_compressed/instruction.rs, update_compressed_mint/instruction.rs}
Updated call sites to use MintActionMetaConfig APIs and meta_config.to_account_metas(); reordered constructor args (payer moved earlier) and removed mint_needs_to_sign usage in CPI-write paths.
New/Refactored ctoken builders
sdk-libs/compressed-token-sdk/src/ctoken/{close.rs,create.rs,compressible.rs,create_cmint.rs,create_ata.rs}
Added struct-based instruction builders and account-info wrappers: CloseAccount, CreateCTokenAccount, CompressibleParams, CreateCMint (and CPI-write variants), new ATA V1/V2 builders; removed legacy function-based token-account builders.
Removed legacy create/token-account modules
sdk-libs/compressed-token-sdk/src/ctoken/create_associated_token_account.rs (deleted), sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/instruction.rs (deleted), sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/mod.rs (export removed)
Deleted old comprehensive ATA / create-token-account implementations; functionality migrated to new struct-based modules (create_ata, create, create_cmint, create_token_account removed/exposed differently).
Mint-to and transfers
sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs, sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken_spl.rs, sdk-libs/compressed-token-sdk/src/ctoken/transfer_spl_ctoken.rs, sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs
Introduced MintToCToken (and CPI-write), TransferCtokenToSpl, TransferSplToCtoken, redesigned TransferInterface with SplInterface; added builders, account-info wrappers, and invoke/invoke_signed helpers.
Module exports & constants
sdk-libs/compressed-token-sdk/src/ctoken/mod.rs, sdk-libs/compressed-token-sdk/src/lib.rs
Reorganized exports to expose new builders/types, added SystemAccountInfos/SystemAccounts, constants COMPRESSIBLE_CONFIG_V1 and RENT_SPONSOR, and re-exported CompressedProof.
Token-client and call-site updates
sdk-libs/token-client/src/actions/*, sdk-libs/token-client/src/instructions/*
Updated imports and call sites to new builders (CreateCTokenAccount, CreateCMint, TransferSplToCtoken, etc.), adjusted parameter names (e.g., todestination_ctoken_account) and constructor arg ordering.
Create CTOKEN account/params additions
sdk-libs/compressed-token-sdk/src/ctoken/compressible.rs, sdk-libs/compressed-token-sdk/src/ctoken/create.rs
Added CompressibleParams, CompressibleParamsInfos, CreateCTokenAccount and CreateCTokenAccountInfos with builder-style APIs and optional rent sponsor wiring.
Create compressed mint
sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
New CreateCMint and CPI-write variants, params structs, account-info conversions, derivation helpers, and instruction builders for compressed-mint creation.
Close and transfer payload tweaks
sdk-libs/compressed-token-sdk/src/ctoken/close.rs, sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken.rs
Replaced free close functions with CloseAccount struct/API; removed extra leading byte in TransferCtoken data construction (data shortened by one byte).
Removed/renamed error & enums
sdk-libs/compressed-token-sdk/src/error.rs
Renamed bridge errors to SplInterface*, removed some create-mint variants, added Missing* variants and updated numeric mappings.
Program-level minimal edits
program-libs/compressed-account/src/instruction_data/traits.rs, programs/compressed-token/program/src/mint_action/{accounts.rs,processor.rs}
Cosmetic whitespace and formatting changes; narrowed has_mint_to_actions predicate in non-CPI AccountsConfig to check MintToCompressed only.
Tests updated
sdk-libs/compressed-token-sdk/tests/create_associated_token_account.rs
Tests adapted to use new CreateAssociatedTokenAccount builder API, CompressibleParams::default(), and derive_ctoken_ata.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant SDK
    participant MetaCfg as MintActionMetaConfig
    participant Program as Solana

    rect rgb(240,250,240)
    Note over Client,SDK: Builder -> MetaCfg -> Instruction flow
    Client->>SDK: Build (e.g., CreateCMint::new(params,...))
    SDK->>MetaCfg: MintActionMetaConfig::new(_payer_, authority, ...)
    alt has MintToCompressed
        SDK->>MetaCfg: .with_mint_compressed_tokens()
    end
    SDK->>MetaCfg: config.to_account_metas()
    MetaCfg->>SDK: Vec<AccountMeta>
    SDK->>Program: assemble Instruction(data + metas)
    SDK->>Program: invoke / invoke_signed
    Program-->>SDK: result
    end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

  • Areas warranting extra attention:
    • MintActionMetaConfig constructors and to_account_metas() — account ordering and signer flags must match program expectations.
    • New ctoken builders (create_ata/create_cmint/create) — discriminators, Borsh serialization, optional compressible-extension wiring, and CPI vs non-CPI account lists.
    • MintToCToken and transfer modules — correct CPI-context handling, proof usage, and token-pool PDA/bump mapping.
    • Removed legacy helpers and re-exports — ensure no remaining call sites rely on deleted functions/paths.
    • Error numeric remapping — validate there are no collisions and consumers handle renamed variants.

Possibly related PRs

Suggested labels

ai-review

Suggested reviewers

  • sergeytimoshin
  • SwenSchaeferjohann

Poem

✨ Builders replace the scattered calls,
Account metas line up in neat halls.
Mints and ATAs find ordered space,
CPI paths steady their pace,
A tidier SDK — steady, small wins, tall.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.26% which is insufficient. The required threshold is 70.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'refactor: ctoken sdk builder instructions2' is somewhat generic and vague. It mentions 'refactor' and 'builder instructions2' but doesn't clearly convey the primary change from a developer scanning history—i.e., the migration to a builder-based SDK pattern for CToken instructions. The '2' suffix suggests continuation but lacks clarity. Consider a more descriptive title like 'refactor: migrate ctoken sdk to builder pattern' or 'refactor: implement ctoken sdk instruction builders' to better communicate the architectural change to future maintainers.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ 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/refactor-ctoken-sdk-builder-instructions2

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.

"sdk-tests/sdk-v1-native-test",
"sdk-tests/sdk-token-test",
"sdk-tests/sdk-compressible-test",
"sdk-tests/sdk-ctoken-test",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

add to ci

@ananas-block ananas-block force-pushed the jorrit/refactor-ctoken-sdk-builder-instructions2 branch from 3eaa52a to 574888f Compare November 22, 2025 00:52
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: 11

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-client/src/instructions/create_mint.rs (1)

43-88: Fix error handling for validity proof results to prevent panics on empty responses

The code currently uses direct indexing and unwrap on RPC results, which will panic if the indexer returns empty collections or missing proofs. Per codebase patterns (e.g., register_forester.rs, compress_and_close_forester.rs), return structured errors instead:

let proof = rpc_result
    .proof
    .0
    .ok_or_else(|| RpcError::CustomError("missing validity proof".to_string()))?;

let first_address = rpc_result
    .addresses
    .get(0)
    .ok_or_else(|| RpcError::CustomError("no addresses returned for compressed mint".to_string()))?;

let address_merkle_tree_root_index = first_address.root_index;

Additionally, version: 3 (line 65) hardcodes protocol knowledge in the client. The on-chain validator checks this value, but if the protocol evolves, consider externalizing this as a constant to avoid silent drift.

sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_to_compressed/instruction.rs (1)

43-57: Required parameters output_queue_tokens, decompressed_mint_config, and token_pool are silently dropped—either remove them from the API or plumb them through

The refactoring centralizes account metas via MintActionMetaConfig, but creates a mismatch between what the function signature accepts and what it actually uses:

  • output_queue_tokens is a required Pubkey, yet it's destructured as _ and the function instead uses output_queue_cmint internally via with_mint_compressed_tokens().
  • decompressed_mint_config and token_pool both carry doc comments stating "Required if the mint is decompressed," yet they too are ignored at lines 52 and 56.
  • A new_decompressed() method exists in MintToCompressedMetaConfig but is never called, so the decompressed path is effectively unavailable.

If a caller attempts to mint to a decompressed account and passes these values, they will be silently lost, causing the program instruction to lack the required accounts. Either remove these fields from MintToCompressedInputs to clarify the API, or plumb them through by detecting the decompressed case and calling the appropriate MintActionMetaConfig constructor (e.g., new_decompressed() when decompressed_mint_config.is_some()).

Also applies to: 75-94

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b09cda4 and 574888f.

⛔ Files ignored due to path filters (60)
  • Cargo.lock is excluded by !**/*.lock and included by none
  • Cargo.toml is excluded by none and included by none
  • program-tests/compressed-token-test/tests/ctoken/compress_and_close.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/ctoken/create.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/ctoken/create_ata.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/ctoken/create_ata2.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/ctoken/functional.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/ctoken/functional_ata.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/ctoken/shared.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/mint/cpi_context.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/mint/edge_cases.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/mint/failing.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/mint/functional.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/mint/random.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/transfer2/compress_failing.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/transfer2/compress_spl_failing.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/transfer2/decompress_failing.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/transfer2/no_system_program_cpi_failing.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/transfer2/shared.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/transfer2/spl_ctoken.rs is excluded by none and included by none
  • program-tests/registry-test/tests/compressible.rs is excluded by none and included by none
  • program-tests/utils/src/assert_create_token_account.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/src/instruction_accounts.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/src/instructions/create_user_record_and_game_session.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/src/instructions/decompress_accounts_idempotent.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/tests/game_session_tests.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/tests/helpers.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/tests/idempotency_tests.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/tests/multi_account_tests.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/Cargo.lock is excluded by !**/*.lock and included by none
  • sdk-tests/sdk-ctoken-test/Cargo.toml is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/README.md is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/Xargo.toml is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/close.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/create_ata.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/create_ata2.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/create_cmint.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/create_token_account.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/lib.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/mint_to_ctoken.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/transfer.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/transfer_interface.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/transfer_spl_ctoken.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/shared.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_close.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_create_ata.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_create_ata_v2.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_create_cmint.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_create_token_account.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_mint_to_ctoken.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_transfer.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_transfer_interface.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_transfer_spl_ctoken.rs is excluded by none and included by none
  • sdk-tests/sdk-token-test/src/process_compress_full_and_close.rs is excluded by none and included by none
  • sdk-tests/sdk-token-test/src/process_create_ctoken_with_compress_to_pubkey.rs is excluded by none and included by none
  • sdk-tests/sdk-token-test/tests/compress_and_close_cpi.rs is excluded by none and included by none
  • sdk-tests/sdk-token-test/tests/decompress_full_cpi.rs is excluded by none and included by none
  • sdk-tests/sdk-token-test/tests/pda_ctoken.rs is excluded by none and included by none
  • sdk-tests/sdk-token-test/tests/test_4_transfer2.rs is excluded by none and included by none
  • sdk-tests/sdk-token-test/tests/test_compress_full_and_close.rs is excluded by none and included by none
📒 Files selected for processing (31)
  • program-libs/compressed-account/src/instruction_data/traits.rs (1 hunks)
  • programs/compressed-token/program/src/mint_action/accounts.rs (1 hunks)
  • programs/compressed-token/program/src/mint_action/processor.rs (0 hunks)
  • sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (3 hunks)
  • sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/mod.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_to_compressed/instruction.rs (3 hunks)
  • sdk-libs/compressed-token-sdk/src/compressed_token/v2/update_compressed_mint/instruction.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/close.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/compressible.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/create.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/create_associated_token_account.rs (0 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/instruction.rs (0 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/mod.rs (0 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/mod.rs (2 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken.rs (0 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken_spl.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (4 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_spl_ctoken.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/error.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/lib.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/tests/create_associated_token_account.rs (3 hunks)
  • sdk-libs/token-client/src/actions/create_compressible_token_account.rs (2 hunks)
  • sdk-libs/token-client/src/actions/mint_action.rs (1 hunks)
  • sdk-libs/token-client/src/actions/transfer2/ctoken_to_spl.rs (1 hunks)
  • sdk-libs/token-client/src/actions/transfer2/spl_to_ctoken.rs (3 hunks)
  • sdk-libs/token-client/src/instructions/create_mint.rs (2 hunks)
  • sdk-libs/token-client/src/instructions/mint_action.rs (3 hunks)
💤 Files with no reviewable changes (5)
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/mod.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/instruction.rs
  • programs/compressed-token/program/src/mint_action/processor.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_associated_token_account.rs
🧰 Additional context used
🧬 Code graph analysis (20)
sdk-libs/token-client/src/actions/mint_action.rs (1)
sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (1)
  • derive_ctoken_ata (20-29)
sdk-libs/token-client/src/actions/transfer2/ctoken_to_spl.rs (1)
sdk-libs/compressed-token-sdk/src/token_pool.rs (1)
  • find_token_pool_pda_with_index (20-28)
sdk-libs/token-client/src/instructions/create_mint.rs (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs (2)
  • derive_compressed_mint_address (193-202)
  • find_spl_mint_address (212-217)
sdk-libs/token-client/src/actions/transfer2/spl_to_ctoken.rs (1)
sdk-libs/compressed-token-sdk/src/token_pool.rs (1)
  • find_token_pool_pda_with_index (20-28)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
  • new_create_mint (22-40)
sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (3)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (3)
  • get_mint_action_instruction_account_metas_cpi_write (181-209)
  • new_cpi_context (64-85)
  • new_create_mint (22-40)
program-libs/compressed-account/src/instruction_data/traits.rs (6)
  • cpi_context (58-58)
  • data (26-34)
  • data (87-87)
  • data (108-108)
  • address (84-84)
  • address (105-105)
program-libs/ctoken-types/src/instructions/mint_action/builder.rs (2)
  • new_mint (44-63)
  • new_mint_write_to_cpi_context (65-84)
sdk-libs/compressed-token-sdk/src/ctoken/compressible.rs (2)
sdk-libs/compressed-token-sdk/src/ctoken/create.rs (2)
  • new (24-38)
  • new (102-116)
sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (3)
  • new (47-63)
  • new (155-174)
  • new (268-284)
sdk-libs/compressed-token-sdk/tests/create_associated_token_account.rs (1)
sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (1)
  • derive_ctoken_ata (20-29)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (1)
sdk-libs/compressed-token-sdk/src/utils.rs (1)
  • is_ctoken_account (22-37)
sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (2)
sdk-libs/compressed-token-sdk/src/ctoken/create.rs (6)
  • invoke (122-138)
  • from (160-178)
  • new (24-38)
  • new (102-116)
  • instruction (40-90)
  • instruction (118-120)
sdk-libs/compressed-token-sdk/src/ctoken/compressible.rs (2)
  • new (33-39)
  • new (57-73)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_spl_ctoken.rs (4)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken_spl.rs (5)
  • invoke (47-61)
  • invoke_signed (63-77)
  • instruction (43-45)
  • instruction (98-158)
  • from (81-93)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/transfer2/instruction.rs (1)
  • create_transfer2_instruction (69-138)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/account2.rs (2)
  • compress_spl (193-220)
  • decompress_ctoken (224-247)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/transfer2/account_metas.rs (1)
  • new_decompressed_accounts_only (33-46)
sdk-libs/token-client/src/instructions/mint_action.rs (2)
sdk-libs/token-client/src/actions/mint_action.rs (1)
  • mint_action (24-59)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
  • new (43-61)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken_spl.rs (4)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_spl_ctoken.rs (5)
  • invoke (48-62)
  • invoke_signed (64-78)
  • instruction (44-46)
  • instruction (98-152)
  • from (82-94)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/transfer2/instruction.rs (1)
  • create_transfer2_instruction (69-138)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/account2.rs (2)
  • compress_ctoken (169-190)
  • decompress_spl (250-279)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/transfer2/account_metas.rs (1)
  • new_decompressed_accounts_only (33-46)
sdk-libs/compressed-token-sdk/src/ctoken/close.rs (1)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken.rs (5)
  • invoke (27-31)
  • invoke_signed (33-37)
  • instruction (23-25)
  • instruction (52-66)
  • from (41-48)
sdk-libs/compressed-token-sdk/src/ctoken/create.rs (2)
sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (11)
  • invoke (185-204)
  • invoke (380-403)
  • new (47-63)
  • new (155-174)
  • new (268-284)
  • instruction (89-140)
  • instruction (181-183)
  • instruction (310-361)
  • instruction (376-378)
  • from (229-249)
  • from (432-452)
sdk-libs/compressed-token-sdk/src/ctoken/compressible.rs (2)
  • new (33-39)
  • new (57-73)
sdk-libs/compressed-token-sdk/src/ctoken/mod.rs (1)
sdk-libs/sdk/src/compressible/close.rs (1)
  • close (6-40)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_to_compressed/instruction.rs (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
  • new (43-61)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
sdk-libs/token-client/src/actions/mint_action.rs (1)
  • mint_action (24-59)
sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs (3)
sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (12)
  • invoke (327-350)
  • invoke_signed (352-375)
  • invoke_signed (421-425)
  • new (66-82)
  • new (170-189)
  • new (215-227)
  • with_cpi_context (84-88)
  • instruction (90-149)
  • instruction (229-280)
  • instruction (323-325)
  • instruction (417-419)
  • from (429-436)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (2)
  • get_mint_action_instruction_account_metas_cpi_write (181-209)
  • new_cpi_context (64-85)
programs/compressed-token/program/src/mint_action/accounts.rs (1)
  • new (379-469)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/mod.rs (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
  • get_mint_action_instruction_account_metas_cpi_write (181-209)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Test batched-merkle-tree-simulate
  • GitHub Check: programs (account-compression-and-registry, ["cargo-test-sbf -p account-compression-test", "cargo...
  • GitHub Check: programs (compressed-token-batched-tree, ["cargo-test-sbf -p compressed-token-test -- test_transf...
🔇 Additional comments (20)
program-libs/compressed-account/src/instruction_data/traits.rs (1)

26-34: Good formatting for clarity between logical sections.

The blank line inserted after the discriminator (line 31) improves readability by visually separating the "add discriminator" step from the "add serialized data" step. No logic or behavioral changes; the trait's public interface and semantics remain intact.

sdk-libs/compressed-token-sdk/src/error.rs (2)

114-114: Verification complete: Error code renumbering is safe internally.

The codebase has no hardcoded references to 17026 or 17024. Error code mapping is centralized in a single From<TokenSdkError> implementation (lines 89–116), and tests use parametric error code comparison rather than hardcoded values. The renumbering creates a contiguous sequence (17001–17024) with no gaps—standard practice when removing error variants.

The original concern about downstream code matching hardcoded error numbers is valid for external consumers, but this codebase shows no such risk. If your error codes are part of a public API contract, consider documenting the change or reserving the gaps for backward compatibility in future releases.


13-74: I'll verify a few more angles to be thorough—let me check if tests or builder code reference these variants, and confirm the compile-time validation moved where expected.

Let me search for the builder code and test references to confirm the constraints moved to compile-time validation:

This is a breaking API change that's safely isolated within the codebase—verify it's intentional and documented for external consumers.

The verification confirms:

  • No references to CreateMintDataRequired or CreateMintMustBeNone exist in the codebase
  • Removing publicly exposed items causes downstream code to fail to compile and is a major semver change
  • The refactoring is sound (builders using the typestate pattern enforce constraints at compile-time rather than runtime)

This is a deliberate breaking change aligned with moving from runtime error handling to compile-time validation. Ensure this is:

  1. Reflected in a major version bump per semver
  2. Documented in changelog/migration guide for external SDK consumers
  3. Tested to confirm no edge cases exist in related error handling code
sdk-libs/compressed-token-sdk/src/lib.rs (1)

14-14: The CompressedProof re-export is correctly justified and intentional.

Verification confirms that CompressedProof is actively used in the public API as a field in the CreateCMintParams struct (line 31 of src/ctoken/create_cmint.rs). Since this struct is public and exported through pub mod ctoken, consumers need direct access to the CompressedProof type—making the re-export at the crate root essential for usability. This is consistent with the params-struct builder pattern introduced in this refactor.

The code change is solid. If you want to further enhance clarity, consider adding a one-line doc comment to this re-export explaining its relationship to the builder API, though this is optional.

programs/compressed-token/program/src/mint_action/accounts.rs (1)

452-458: Aligning has_mint_to_actions with actual queue usage looks correct

Restricting has_mint_to_actions to MintToCompressed here matches how tokens_out_queue is used (only new compressed outputs require that queue) and brings the non‑CPI path in line with the CPI path logic above. I don’t see other usages of has_mint_to_actions in this file that would still need MintToCToken, so this tightening looks safe and more accurate.

sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (3)

4-77: TransferInterface SPL bridge wiring and routing look sound

The Split of the SPL-bridge metadata into SplBridgeConfig and the TransferInterface::with_spl_bridge builder reads clean, and the routing based on is_ctoken_account for the three supported cases (ctoken↔ctoken, ctoken→SPL, SPL→ctoken) is consistent. The IncompleteSplBridgeConfig error on missing bridge config is an appropriate guardrail.


155-176: Field rename to destination_ctoken_account is consistent with the SPL→ctoken helpers

Using destination_ctoken_account here matches the TransferSplToCtokenAccountInfos struct in transfer_spl_ctoken.rs and keeps the SPL→ctoken path aligned between regular and signed invokes. No issues spotted with the account mapping.


224-244: Signed SPL→ctoken path mirrors the unsigned variant correctly

The invoke_signed branch mirrors the unsigned case, including the destination_ctoken_account mapping and IncompleteSplBridgeConfig guard, so the signer‑seed variant should behave identically aside from the additional signing power.

sdk-libs/compressed-token-sdk/src/ctoken/compressible.rs (1)

1-79: Compressible params builders are consistent with the create flows

The CompressibleParams and CompressibleParamsInfos defaults and new/with_compress_to_pubkey builders line up with how they’re consumed in create.rs and create_ata.rs (rent_payment, top‑up, version, and optional compress‑to pubkey). The shapes look correct and future‑proof for passing through additional compressible config as needed.

sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken_spl.rs (3)

17-40: CToken→SPL account-info structs match the intended bridge surface

The TransferCtokenToSpl and TransferCtokenToSplAccountInfos shapes capture exactly the accounts needed for the two‑step bridge (ctoken source, SPL dest, pool, mint, payer, program authority, SPL token program), and the conversion From<&…> is a straightforward key/amount copy. No structural issues here.


47-77: CPI invoke helpers are consistent with the meta layout

The invoke/invoke_signed helpers respect the “cpi_authority PDA, fee_payer, packed accounts…” ordering used elsewhere (e.g., SPL→ctoken), so the account slice should line up with the metas produced by TransferCtokenToSpl::instruction. This keeps the CPI surface predictable.


96-158: Index wiring for compress/decompress steps looks correct

The two CTokenAccount2 entries use indices that match the packed metas:

  • compress_ctoken(self.amount, 0, 1, 3) → mint at 0, source ctoken at 1, authority at 3.
  • decompress_spl(self.amount, 0, 2, 4, 0, self.token_pool_pda_bump) → mint at 0, destination SPL at 2, pool PDA at 4, pool index 0, bump from token_pool_pda_bump.

Given the packed accounts [mint, source_ctoken, dest_spl, authority, pool_pda, spl_program], this wiring matches the transfer2 conventions and mirrors the existing SPL→ctoken implementation.

sdk-libs/compressed-token-sdk/src/ctoken/create.rs (2)

14-90: CreateCTokenAccount builder and account metas look consistent with the ATA path

The instruction builder correctly:

  • Encodes the optional compressible extension (version, rent epochs, top‑up presence, optional compress‑to pubkey).
  • Prepends the expected InitializeAccount3 discriminator byte.
  • Builds two account layouts:
    • Compressible: [account, mint, payer, compressible_config, system_program, rent_sponsor].
    • Non‑compressible: [account, mint].

This matches the patterns used in create_ata.rs for compressible vs non‑compressible initialization, including the convention of passing the real system_program account via infos while using a placeholder key in the metas.


159-178: Infos→builder conversion preserves compressible settings correctly

The From<&CreateCTokenAccountInfos<'info>> for CreateCTokenAccount implementation faithfully maps:

  • Payer/account/mint/owner pubkeys, and
  • All compressible parameters (config pubkey, rent_sponsor, epochs, lamports_per_write, optional compress_to_account_pubkey, token_account_version).

Dropping system_program from the params is intentional and keeps CompressibleParams focused on config rather than CPI plumbing.

sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (1)

15-29: PDA derivation and discriminators follow existing compressed-token patterns

The derive_ctoken_ata seeds and program id usage match the rest of the compressed-token SDK conventions, and the discriminator constants are clearly separated for V1/V2 and idempotent variants. I don’t see any functional issues here assuming these values match the on-chain program spec.

sdk-libs/token-client/src/actions/mint_action.rs (1)

101-112: Importing ctoken::derive_ctoken_ata aligns with the new API surface

Switching to light_compressed_token_sdk::ctoken::derive_ctoken_ata keeps the mint-to-ctoken ATA derivation logic intact while reflecting the new consolidated ctokens module layout. The usage in mint_action_comprehensive looks correct.

sdk-libs/token-client/src/actions/transfer2/ctoken_to_spl.rs (1)

5-7: Updated TransferCtokenToSpl import matches the new ctokens module layout

The move from ctoken::transfer_interface::TransferCtokenToSpl to ctoken::TransferCtokenToSpl is consistent with the refactor and keeps the transfer construction unchanged.

sdk-libs/token-client/src/actions/transfer2/spl_to_ctoken.rs (1)

5-7: Renaming to destination_ctoken_account improves clarity with no behavioral change

Using TransferSplToCtoken from the ctoken root and renaming the parameter/field from to to destination_ctoken_account makes the direction of value flow much clearer. The struct construction matches the new field name, so everything stays consistent.

Also applies to: 19-20, 36-41

sdk-libs/token-client/src/actions/create_compressible_token_account.rs (1)

57-74: Good refactor to CompressibleParams + CreateCTokenAccount builder; just verify param semantics

The move to CompressibleParams and CreateCTokenAccount::new(...).instruction() keeps all the previous inputs flowing through (config PDA, rent sponsor, prepaid epochs, optional lamports_per_write, and token_account_version), which makes the behavior easier to reason about.

Two minor points to double-check:

  • Confirm that pre_pay_num_epochs: num_prepaid_epochs and lamports_per_write line up with the on-chain struct definition (no widening/narrowing issues or changed units).
  • If the SDK offers a CompressibleParams::new / default_for_version helper, using that instead of an open struct literal would reduce the chance of missing fields when the struct evolves.

Otherwise the wiring here looks solid.

sdk-libs/compressed-token-sdk/tests/create_associated_token_account.rs (1)

1-27: Solid coverage of the new ATA builder + compressible params

These test updates look good: they exercise

  • Discriminator selection for regular vs idempotent forms.
  • Data and account-list consistency between the two paths.
  • new_with_bump variants for both non-idempotent and idempotent.
  • The expected account count when CompressibleParams::default() is used.

That’s a nice safety net for the new CreateAssociatedTokenAccount builder surface and should catch regressions in discriminator wiring or account metas.

Also applies to: 34-47, 57-87, 89-102

Comment on lines 83 to 101
let meta_config = if cpi_context_pubkey.is_some() {
MintActionMetaConfig::new_cpi_context(
&instruction_data,
input.mint_authority,
input.payer,
input.mint_authority,
cpi_context_pubkey.unwrap(),
)?
} else {
MintActionMetaConfig::new_create_mint(
&instruction_data,
input.payer,
input.mint_authority,
input.mint_signer,
input.payer,
input.address_tree_pubkey,
input.output_queue,
)?
)
};

let account_metas =
get_mint_action_instruction_account_metas(meta_config, &compressed_mint_with_context);
let account_metas = meta_config.to_account_metas();

Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Meta-config branch looks correct; consider simplifying Option handling

The switch to MintActionMetaConfig::new_cpi_context / new_create_mint plus to_account_metas() keeps behavior centralized, which is a good refactor.

You can make this a bit cleaner (and avoid is_some + unwrap) by matching the Option directly:

-    let meta_config = if cpi_context_pubkey.is_some() {
-        MintActionMetaConfig::new_cpi_context(
-            &instruction_data,
-            input.payer,
-            input.mint_authority,
-            cpi_context_pubkey.unwrap(),
-        )?
-    } else {
-        MintActionMetaConfig::new_create_mint(
-            input.payer,
-            input.mint_authority,
-            input.mint_signer,
-            input.address_tree_pubkey,
-            input.output_queue,
-        )
-    };
+    let meta_config = if let Some(cpi_pubkey) = cpi_context_pubkey {
+        MintActionMetaConfig::new_cpi_context(
+            &instruction_data,
+            input.payer,
+            input.mint_authority,
+            cpi_pubkey,
+        )?
+    } else {
+        MintActionMetaConfig::new_create_mint(
+            input.payer,
+            input.mint_authority,
+            input.mint_signer,
+            input.address_tree_pubkey,
+            input.output_queue,
+        )
+    };
🤖 Prompt for AI Agents
In
sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs
around lines 83 to 101, the current code uses cpi_context_pubkey.is_some()
combined with cpi_context_pubkey.unwrap(), which is unnecessary and brittle;
replace that pattern by matching the Option directly (e.g., use match or if let
Some(pubkey) = cpi_context_pubkey { ... } else { ... }) to call
MintActionMetaConfig::new_cpi_context(pubkey, ...) in the Some branch and
MintActionMetaConfig::new_create_mint(...) in the None branch, preserving the
existing error propagation (?) and then call meta_config.to_account_metas() as
before.

Comment on lines +147 to +161
metas.push(AccountMeta::new(self.output_queue, false));

metas.push(AccountMeta::new(config.tree_pubkey, false));
metas.push(AccountMeta::new(self.tree_pubkey, false));

if !config.create_mint {
if let Some(input_queue) = config.input_queue {
metas.push(AccountMeta::new(input_queue, false));
// input_queue is present when NOT creating a new mint (mint_signer.is_none())
if self.mint_signer.is_none() {
if let Some(input_queue) = self.input_queue {
metas.push(AccountMeta::new(input_queue, false));
}
}
}

if config.has_mint_to_actions {
let tokens_out_queue = config.tokens_out_queue.unwrap_or(config.output_queue);
metas.push(AccountMeta::new(tokens_out_queue, false));
}
// tokens_out_queue is present when there are MintToCompressed actions
if let Some(tokens_out_queue) = self.tokens_out_queue {
metas.push(AccountMeta::new(tokens_out_queue, false));
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Skip queue/tree metas when cpi_context is present

MintActionMetaConfig::new_cpi_context deliberately fills tree_pubkey and output_queue with Pubkey::default(). Because to_account_metas still pushes those slots (and the derived input_queue / tokens_out_queue) we hand back instructions that require the system program in those positions. The CPI helpers (for example MintToCTokenInfos::invoke) then feed the real queue/tree accounts and the runtime throws InstructionError::AccountMismatch immediately. Gate the queue-related metas behind the non-CPI path so CPI callers no longer desync the account list.

Apply this diff to keep queue-related metas out of the CPI-context case:

-        metas.push(AccountMeta::new(self.output_queue, false));
-
-        metas.push(AccountMeta::new(self.tree_pubkey, false));
-
-        // input_queue is present when NOT creating a new mint (mint_signer.is_none())
-        if self.mint_signer.is_none() {
-            if let Some(input_queue) = self.input_queue {
-                metas.push(AccountMeta::new(input_queue, false));
-            }
-        }
-
-        // tokens_out_queue is present when there are MintToCompressed actions
-        if let Some(tokens_out_queue) = self.tokens_out_queue {
-            metas.push(AccountMeta::new(tokens_out_queue, false));
-        }
+        if self.cpi_context.is_none() {
+            metas.push(AccountMeta::new(self.output_queue, false));
+            metas.push(AccountMeta::new(self.tree_pubkey, false));
+
+            // input_queue is present when NOT creating a new mint (mint_signer.is_none())
+            if self.mint_signer.is_none() {
+                if let Some(input_queue) = self.input_queue {
+                    metas.push(AccountMeta::new(input_queue, false));
+                }
+            }
+
+            // tokens_out_queue is present when there are MintToCompressed actions
+            if let Some(tokens_out_queue) = self.tokens_out_queue {
+                metas.push(AccountMeta::new(tokens_out_queue, false));
+            }
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
metas.push(AccountMeta::new(self.output_queue, false));
metas.push(AccountMeta::new(config.tree_pubkey, false));
metas.push(AccountMeta::new(self.tree_pubkey, false));
if !config.create_mint {
if let Some(input_queue) = config.input_queue {
metas.push(AccountMeta::new(input_queue, false));
// input_queue is present when NOT creating a new mint (mint_signer.is_none())
if self.mint_signer.is_none() {
if let Some(input_queue) = self.input_queue {
metas.push(AccountMeta::new(input_queue, false));
}
}
}
if config.has_mint_to_actions {
let tokens_out_queue = config.tokens_out_queue.unwrap_or(config.output_queue);
metas.push(AccountMeta::new(tokens_out_queue, false));
}
// tokens_out_queue is present when there are MintToCompressed actions
if let Some(tokens_out_queue) = self.tokens_out_queue {
metas.push(AccountMeta::new(tokens_out_queue, false));
}
if self.cpi_context.is_none() {
metas.push(AccountMeta::new(self.output_queue, false));
metas.push(AccountMeta::new(self.tree_pubkey, false));
// input_queue is present when NOT creating a new mint (mint_signer.is_none())
if self.mint_signer.is_none() {
if let Some(input_queue) = self.input_queue {
metas.push(AccountMeta::new(input_queue, false));
}
}
// tokens_out_queue is present when there are MintToCompressed actions
if let Some(tokens_out_queue) = self.tokens_out_queue {
metas.push(AccountMeta::new(tokens_out_queue, false));
}
}

Comment on lines +93 to +157
pub struct CreateCTokenAccountInfos<'info> {
pub payer: AccountInfo<'info>,
pub account: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
pub owner: Pubkey,
pub compressible: Option<CompressibleParamsInfos<'info>>,
}

impl<'info> CreateCTokenAccountInfos<'info> {
pub fn new(
payer: AccountInfo<'info>,
account: AccountInfo<'info>,
mint: AccountInfo<'info>,
owner: Pubkey,
compressible: CompressibleParamsInfos<'info>,
) -> Self {
Self {
payer,
account,
mint,
owner,
compressible: Some(compressible),
}
}

pub fn instruction(&self) -> Result<Instruction, ProgramError> {
CreateCTokenAccount::from(self).instruction()
}

pub fn invoke(self) -> Result<(), ProgramError> {
let instruction = self.instruction()?;
if let Some(compressible) = self.compressible {
let account_infos = [
self.account,
self.mint,
self.payer,
compressible.compressible_config,
compressible.system_program,
compressible.rent_sponsor,
];
invoke(&instruction, &account_infos)
} else {
let account_infos = [self.account, self.mint];
invoke(&instruction, &account_infos)
}
}

pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
let instruction = self.instruction()?;
if let Some(compressible) = self.compressible {
let account_infos = [
self.account,
self.mint,
self.payer,
compressible.compressible_config,
compressible.system_program,
compressible.rent_sponsor,
];
invoke_signed(&instruction, &account_infos, signer_seeds)
} else {
let account_infos = [self.account, self.mint];
invoke_signed(&instruction, &account_infos, signer_seeds)
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Double‑check signer semantics for the non‑compressible create path

In the compressible path, the account meta is created with AccountMeta::new(self.account, true), but in the non‑compressible path it’s AccountMeta::new(self.account, false). For InitializeAccount3‑style flows it’s common for the account being initialized to be a signer regardless of whether a compressible extension is present.

If the underlying ctoken program enforces account.is_signer for non‑compressible initializes as well, this asymmetry could either cause failures or weaken the check. Please confirm the program’s expectation and, if it should always be a signer, change the non‑compressible branch to:

-            vec![
-                AccountMeta::new(self.account, false),
-                AccountMeta::new_readonly(self.mint, false),
-            ]
+            vec![
+                AccountMeta::new(self.account, true),
+                AccountMeta::new_readonly(self.mint, false),
+            ]

Committable suggestion skipped: line range outside the PR's diff.

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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/update_compressed_mint/instruction.rs (1)

135-143: CPI-write meta-config for authority updates is reasonable; consider future unification

Using MintActionMetaConfigCpiWrite { fee_payer: inputs.payer, mint_signer: None, authority: inputs.authority, cpi_context: inputs.cpi_context_pubkey } for authority-only updates makes sense and matches the intent that no mint signer is required on this path.

If MintActionMetaConfigCpiWrite ever grows a to_account_metas() helper similar to MintActionMetaConfig, you might later align this with the create/update flows by calling that instead of get_mint_action_instruction_account_metas_cpi_write(meta_config), but that’s purely a consistency/nicety, not a blocker.

♻️ Duplicate comments (12)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/mod.rs (1)

5-8: Public re-exports still drop the non‑CPI helper; confirm compatibility and migration path

This module now only re‑exports the CPI helper plus the config types. If any external crates previously pulled in the non‑CPI get_mint_action_instruction_account_metas via this module, they will still break on upgrade, even though MintActionMetaConfig::to_account_metas() is the new preferred path.

If the intent is a clean break, that’s fine, but it’s worth explicitly verifying that no external crates rely on the old symbol, or providing a deprecated compatibility shim (thin wrapper calling MintActionMetaConfig::to_account_metas()) for one release to ease migration.

#!/bin/bash
# Scan the workspace for any remaining uses of the old helper name.
rg -n "get_mint_action_instruction_account_metas" --type rust || echo "No direct usages found"
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_to_compressed/instruction.rs (1)

10-14: Meta-config refactor is solid; clean up Option handling and unused inputs

The move to MintActionMetaConfig::new(...).with_mint_compressed_tokens().to_account_metas() is a nice consolidation of account-metas logic for the mint-to-compressed path.

Two small follow‑ups here:

  1. The cpi_context_pubkey.is_some() + unwrap() pattern is still a bit brittle; matching the Option directly is clearer and avoids any future refactors accidentally separating the check from the unwrap. For example:
-    let meta_config = if cpi_context_pubkey.is_some() {
-        MintActionMetaConfig::new_cpi_context(
-            &instruction_data,
-            payer,
-            mint_authority,
-            cpi_context_pubkey.unwrap(),
-        )?
-    } else {
+    let meta_config = if let Some(cpi_pubkey) = cpi_context_pubkey {
+        MintActionMetaConfig::new_cpi_context(
+            &instruction_data,
+            payer,
+            mint_authority,
+            cpi_pubkey,
+        )?
+    } else {
         MintActionMetaConfig::new(
             payer,
             mint_authority,
             state_merkle_tree,
             input_queue,
             output_queue_cmint,
         )
         .with_mint_compressed_tokens()
     };
  1. output_queue_tokens, decompressed_mint_config, and token_pool are now destructured as _. If they’re no longer needed for this flow, consider dropping them from MintToCompressedInputs (or adding a brief comment/TODO) to keep the API surface focused and avoid confusion for callers.

Also applies to: 43-57, 75-91, 93-104

sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs (1)

83-101: Use direct Option matching in meta_config branch to avoid unwrap

The switch to MintActionMetaConfig::new_cpi_context / new_create_mint plus .to_account_metas() is a good cleanup and keeps account-metas logic centralized.

You can simplify the CPI/non‑CPI branch and avoid the is_some + unwrap pair by matching cpi_context_pubkey directly, as noted in the earlier review:

-    let meta_config = if cpi_context_pubkey.is_some() {
-        MintActionMetaConfig::new_cpi_context(
-            &instruction_data,
-            input.payer,
-            input.mint_authority,
-            cpi_context_pubkey.unwrap(),
-        )?
-    } else {
-        MintActionMetaConfig::new_create_mint(
-            input.payer,
-            input.mint_authority,
-            input.mint_signer,
-            input.address_tree_pubkey,
-            input.output_queue,
-        )
-    };
+    let meta_config = if let Some(cpi_pubkey) = cpi_context_pubkey {
+        MintActionMetaConfig::new_cpi_context(
+            &instruction_data,
+            input.payer,
+            input.mint_authority,
+            cpi_pubkey,
+        )?
+    } else {
+        MintActionMetaConfig::new_create_mint(
+            input.payer,
+            input.mint_authority,
+            input.mint_signer,
+            input.address_tree_pubkey,
+            input.output_queue,
+        )
+    };

This keeps the two branches symmetric and removes the chance of drift between the is_some check and the unwrap.

sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (1)

80-112: Please resolve the lingering commented-out builder stub.

This with_spl_source_optional block was already called out in an earlier review. Leaving a half-implemented pattern in comments keeps the API surface confusing. Either finish the helper (with proper error handling and ownership checks) or drop it so downstream users aren’t tempted to cargo-cult incomplete code.

sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs (2)

374-391: CPI write helper omits required base accounts.

get_mint_action_instruction_account_metas_cpi_write emits metas in the order: light system program, mint signer (optional), authority, fee payer, CPI authority PDA, then the CPI context account. Here we only pass [payer, cpi_context_account, ...ctoken_accounts], so the very first lookup mismatches and the CPI immediately fails. Thread the authority and the default system accounts through this struct and build the account_infos slice in the same order as the metas.

Apply a change along these lines:

-pub struct MintToCTokenCpiWriteInfos<'info> {
-    pub payer: AccountInfo<'info>,
-    pub cpi_context_account: AccountInfo<'info>,
-    pub ctoken_accounts: Vec<AccountInfo<'info>>,
-    pub params: MintToCTokenCpiWriteParams,
-}
+pub struct MintToCTokenCpiWriteInfos<'info> {
+    pub authority: AccountInfo<'info>,
+    pub payer: AccountInfo<'info>,
+    pub system_accounts: crate::ctoken::SystemAccountInfos<'info>,
+    pub cpi_context_account: AccountInfo<'info>,
+    pub ctoken_accounts: Vec<AccountInfo<'info>>,
+    pub params: MintToCTokenCpiWriteParams,
+}
@@
-        let instruction = self.instruction()?;
-        let mut account_infos = vec![self.payer, self.cpi_context_account];
-        account_infos.extend(self.ctoken_accounts);
+        let instruction = self.instruction()?;
+        let mut account_infos = vec![
+            self.system_accounts.light_system_program,
+            self.authority,
+            self.payer,
+            self.system_accounts.cpi_authority_pda,
+            self.cpi_context_account,
+        ];
+        account_infos.extend(self.ctoken_accounts);
         invoke_signed(&instruction, &account_infos, signer_seeds)

Also validate in the From/TryFrom impl that params.mint_authority matches the provided authority key before forwarding.


286-335: CPI path still misorders account infos.

When cpi_context is set, MintActionMetaConfig::new_cpi_context omits the tree/queue metas and instead expects the CPI context account immediately after the system slots. We still append output/state/input before pushing cpi_context_account, so the runtime hits InstructionError::AccountMismatch the moment the CPI helper is exercised. Please gate the queue trio behind self.cpi_context.is_none() and push the CPI context account before extending ctoken accounts (apply the same fix in invoke_signed).

Apply this diff to both invoke and invoke_signed:

-        let mut account_infos = vec![
-            self.system_accounts.light_system_program,
-            self.authority,
-            self.payer,
-            self.system_accounts.cpi_authority_pda,
-            self.system_accounts.registered_program_pda,
-            self.system_accounts.account_compression_authority,
-            self.system_accounts.account_compression_program,
-            self.system_accounts.system_program,
-            self.output_queue,
-            self.state_tree,
-            self.input_queue,
-        ];
-
-        account_infos.extend(self.ctoken_accounts);
-
-        if let Some(cpi_context_account) = self.cpi_context_account {
-            account_infos.push(cpi_context_account);
-        }
+        let mut account_infos = vec![
+            self.system_accounts.light_system_program,
+            self.authority,
+            self.payer,
+            self.system_accounts.cpi_authority_pda,
+            self.system_accounts.registered_program_pda,
+            self.system_accounts.account_compression_authority,
+            self.system_accounts.account_compression_program,
+            self.system_accounts.system_program,
+        ];
+
+        if let Some(cpi_context_account) = self.cpi_context_account {
+            account_infos.push(cpi_context_account);
+        } else {
+            account_infos.push(self.output_queue);
+            account_infos.push(self.state_tree);
+            account_infos.push(self.input_queue);
+        }
+
+        account_infos.extend(self.ctoken_accounts);
sdk-libs/compressed-token-sdk/src/ctoken/close.rs (1)

69-88: Missing token program AccountInfo in CPI helpers

CloseAccountInfos::invoke and invoke_signed still omit self.token_program from the account_infos slice, even though Instruction::program_id is set to that pubkey. For SPL/ctoken CPIs you must include the program’s AccountInfo in the slice or the runtime will fail dispatching the call.

You likely want account_infos to include self.token_program as the last element in both branches:

    pub fn invoke(self) -> Result<(), ProgramError> {
        let instruction = self.instruction()?;
        if let Some(rent_sponsor) = self.rent_sponsor {
-            let account_infos = [self.account, self.destination, self.owner, rent_sponsor];
+            let account_infos = [
+                self.account,
+                self.destination,
+                self.owner,
+                rent_sponsor,
+                self.token_program,
+            ];
             invoke(&instruction, &account_infos)
        } else {
-            let account_infos = [self.account, self.destination, self.owner];
+            let account_infos = [
+                self.account,
+                self.destination,
+                self.owner,
+                self.token_program,
+            ];
             invoke(&instruction, &account_infos)
        }
    }

    pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
        let instruction = self.instruction()?;
        if let Some(rent_sponsor) = self.rent_sponsor {
-            let account_infos = [self.account, self.destination, self.owner, rent_sponsor];
+            let account_infos = [
+                self.account,
+                self.destination,
+                self.owner,
+                rent_sponsor,
+                self.token_program,
+            ];
             invoke_signed(&instruction, &account_infos, signer_seeds)
        } else {
-            let account_infos = [self.account, self.destination, self.owner];
+            let account_infos = [
+                self.account,
+                self.destination,
+                self.owner,
+                self.token_program,
+            ];
             invoke_signed(&instruction, &account_infos, signer_seeds)
        }
    }
sdk-libs/compressed-token-sdk/src/ctoken/create.rs (1)

40-90: Fix system program meta for compressible accounts and re‑check signer flag for non‑compressible accounts

Two related issues in CreateCTokenAccount::instruction:

  1. System program meta uses Pubkey::default()

    In the compressible branch:

    AccountMeta::new_readonly(Pubkey::default(), false), // system_program

    but in the CPI helpers you pass compressible.system_program as the corresponding AccountInfo. That means:

    • instruction.accounts[4].pubkey is all‑zeros.
    • The AccountInfo at the same index in invoke/invoke_signed is the real system program account.

    This mismatch will cause the runtime to reject the instruction (and the ctoken program itself is very likely to check that the supplied system program matches the expected ID).

    You should wire the actual system program ID here, e.g. via whatever system‑program constant this workspace exposes (pseudo‑code):

    -                AccountMeta::new_readonly(Pubkey::default(), false), // system_program
    +                AccountMeta::new_readonly(system_program_id(), false), // system_program

    where system_program_id() is the appropriate helper/constant for the Solana system program in this repo.

  2. Non‑compressible account signer semantics

    In the non‑compressible branch you use:

    AccountMeta::new(self.account, false),

    whereas the compressible branch marks self.account as a signer:

    AccountMeta::new(self.account, true),

    For InitializeAccount3‑style flows it’s common for the token account being initialized to be a signer regardless of extension, so this asymmetry is worth re‑confirming against the on‑chain program’s expectations.

    If the ctoken program requires the account to be a signer in both cases, consider:

    -            vec![
    -                AccountMeta::new(self.account, false),
    -                AccountMeta::new_readonly(self.mint, false),
    -            ]
    +            vec![
    +                AccountMeta::new(self.account, true),
    +                AccountMeta::new_readonly(self.mint, false),
    +            ]
sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (2)

35-44: compressible is modelled as optional but ctors always force Some(...)

Both CreateAssociatedTokenAccount and CreateAssociatedTokenAccount2 store compressible: Option<CompressibleParams>, and the corresponding *Infos structs carry Option<CompressibleParamsInfos<'info>>. However, all the provided constructors (new, new_with_bump, and CreateAssociatedTokenAccountInfos::new) require a non‑optional CompressibleParams* and always wrap it in Some(...). The only way to produce a non‑compressible ATA is via manual struct construction, which is easy to miss at the call sites. This is the same concern that was raised in the earlier review.

If non‑compressible CTOKEN ATAs are valid, consider either:

  • Letting the ctors take Option<CompressibleParams> / Option<CompressibleParamsInfos<'info>> and propagate that directly, or
  • Adding explicit helpers like new_without_compressible(...) and new_with_bump_without_compressible(...).

If non‑compressible ATAs are not valid, changing the field type to CompressibleParams / CompressibleParamsInfos<'info> would make the API intent clearer.

Also applies to: 46-83, 143-152, 154-174, 256-265, 267-303, 364-373


90-103: ATA flows still drop compress_to_account_pubkey; document or propagate it

In both V1 and V2 builders, CompressibleExtensionInstructionData and the From<&...Infos> for ... conversions hard‑code:

compress_to_account_pubkey: None,

ignoring any compress_to_account_pubkey that might be present in CompressibleParams / CompressibleParamsInfos<'info>. That’s different from the create.rs flow, where this field is propagated from the infos into the instruction data. This matches a concern already raised in a previous review.

If ATA creation should never customize compress_to_account_pubkey, this is fine but deserves an explicit comment (e.g. “ATAs always compress to their own address; overrides are ignored”). If you expect to support non‑default compress targets for ATAs later, it would be safer to propagate the field now for consistency with CreateCTokenAccount.

Also applies to: 228-247, 310-324, 431-449

sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)

63-85: CPI context still emits queue/tree metas with default pubkeys, causing account mismatch

MintActionMetaConfig::new_cpi_context intentionally sets:

tree_pubkey: Pubkey::default(),
output_queue: Pubkey::default(),
mint_signer: None,
input_queue: None,
cpi_context: Some(cpi_context_pubkey),

but to_account_metas always pushes self.output_queue and self.tree_pubkey, and may also push input_queue / tokens_out_queue. For CPI callers, helper structs like CreateCMintAccountInfos::invoke* (and similar mint/transfer helpers) provide real queue/tree AccountInfos in these positions. The result is an Instruction whose metas contain zeroed pubkeys at those indices, while the supplied AccountInfos hold real keys — the Solana runtime will reject this with InstructionError::AccountMismatch before your program executes. This is exactly the issue called out in the earlier review; it’s still present after the refactor.

To fix it, gate queue‑related metas behind the non‑CPI path, along the lines of the earlier suggestion:

-        metas.push(AccountMeta::new(self.output_queue, false));
-
-        metas.push(AccountMeta::new(self.tree_pubkey, false));
-
-        // input_queue is present when NOT creating a new mint (mint_signer.is_none())
-        if self.mint_signer.is_none() {
-            if let Some(input_queue) = self.input_queue {
-                metas.push(AccountMeta::new(input_queue, false));
-            }
-        }
-
-        // tokens_out_queue is present when there are MintToCompressed actions
-        if let Some(tokens_out_queue) = self.tokens_out_queue {
-            metas.push(AccountMeta::new(tokens_out_queue, false));
-        }
+        if self.cpi_context.is_none() {
+            metas.push(AccountMeta::new(self.output_queue, false));
+            metas.push(AccountMeta::new(self.tree_pubkey, false));
+
+            // input_queue is present when NOT creating a new mint (mint_signer.is_none())
+            if self.mint_signer.is_none() {
+                if let Some(input_queue) = self.input_queue {
+                    metas.push(AccountMeta::new(input_queue, false));
+                }
+            }
+
+            // tokens_out_queue is present when there are MintToCompressed actions
+            if let Some(tokens_out_queue) = self.tokens_out_queue {
+                metas.push(AccountMeta::new(tokens_out_queue, false));
+            }
+        }

You’ll also want to ensure the various *AccountInfos::invoke* helpers only pass queue/tree accounts in the non‑CPI case so the account slices stay aligned.

Also applies to: 97-168

sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (1)

206-212: CPI‑write mint path still passes too few and misordered accounts to invoke_signed

CreateCompressedMintCpiWrite::instruction builds a CPI‑write mint action using:

let meta_config = MintActionMetaConfigCpiWrite {
    fee_payer: self.payer,
    mint_signer: Some(self.mint_signer),
    authority: self.params.mint_authority,
    cpi_context: self.cpi_context_pubkey,
};
let account_metas = get_mint_action_instruction_account_metas_cpi_write(meta_config);

and get_mint_action_instruction_account_metas_cpi_write emits metas for:

  1. Light system program
  2. Optional mint signer
  3. Authority (signer)
  4. Fee payer (signer)
  5. CPI authority PDA
  6. CPI context account

But CreateCompressedMintCpiWriteInfos::invoke_signed currently supplies only:

let account_infos = [self.mint_signer, self.payer, self.cpi_context_account];
invoke_signed(&instruction, &account_infos, signer_seeds)

so the runtime sees fewer accounts than described in the Instruction and cannot match them to the metas — this will fail immediately with a missing/mismatched account error. This is the same issue called out in the earlier review.

You already have SystemAccountInfos<'info> in this module; a minimal fix is to extend CreateCompressedMintCpiWriteInfos and its invoke_signed to pass the full set of accounts expected by the metas, e.g.:

 pub struct CreateCompressedMintCpiWriteInfos<'info> {
-    pub mint_signer: AccountInfo<'info>,
-    pub payer: AccountInfo<'info>,
-    pub cpi_context_account: AccountInfo<'info>,
+    pub mint_signer: AccountInfo<'info>,
+    pub authority: AccountInfo<'info>,
+    pub payer: AccountInfo<'info>,
+    pub system_accounts: SystemAccountInfos<'info>,
+    pub cpi_context_account: AccountInfo<'info>,
     pub params: CreateCMintCpiWriteParams,
 }

 pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
     let instruction = self.instruction()?;
-    let account_infos = [self.mint_signer, self.payer, self.cpi_context_account];
+    let account_infos = [
+        self.system_accounts.light_system_program,
+        self.mint_signer,
+        self.authority,
+        self.payer,
+        self.system_accounts.cpi_authority_pda,
+        self.cpi_context_account,
+    ];
     invoke_signed(&instruction, &account_infos, signer_seeds)
 }

Adjust the From<&CreateCompressedMintCpiWriteInfos<'info>> for CreateCompressedMintCpiWrite impl and call sites accordingly. This will bring the CPI‑write path in line with the account metas it advertises.

Also applies to: 229-280, 409-425

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b09cda4 and 6757675.

⛔ Files ignored due to path filters (60)
  • Cargo.lock is excluded by !**/*.lock and included by none
  • Cargo.toml is excluded by none and included by none
  • program-tests/compressed-token-test/tests/ctoken/compress_and_close.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/ctoken/create.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/ctoken/create_ata.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/ctoken/create_ata2.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/ctoken/functional.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/ctoken/functional_ata.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/ctoken/shared.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/mint/cpi_context.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/mint/edge_cases.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/mint/failing.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/mint/functional.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/mint/random.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/transfer2/compress_failing.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/transfer2/compress_spl_failing.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/transfer2/decompress_failing.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/transfer2/no_system_program_cpi_failing.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/transfer2/shared.rs is excluded by none and included by none
  • program-tests/compressed-token-test/tests/transfer2/spl_ctoken.rs is excluded by none and included by none
  • program-tests/registry-test/tests/compressible.rs is excluded by none and included by none
  • program-tests/utils/src/assert_create_token_account.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/src/instruction_accounts.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/src/instructions/create_user_record_and_game_session.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/src/instructions/decompress_accounts_idempotent.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/tests/game_session_tests.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/tests/helpers.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/tests/idempotency_tests.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/tests/multi_account_tests.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/Cargo.lock is excluded by !**/*.lock and included by none
  • sdk-tests/sdk-ctoken-test/Cargo.toml is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/README.md is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/Xargo.toml is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/close.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/create_ata.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/create_ata2.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/create_cmint.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/create_token_account.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/lib.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/mint_to_ctoken.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/transfer.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/transfer_interface.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/transfer_spl_ctoken.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/shared.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_close.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_create_ata.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_create_ata_v2.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_create_cmint.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_create_token_account.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_mint_to_ctoken.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_transfer.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_transfer_interface.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_transfer_spl_ctoken.rs is excluded by none and included by none
  • sdk-tests/sdk-token-test/src/process_compress_full_and_close.rs is excluded by none and included by none
  • sdk-tests/sdk-token-test/src/process_create_ctoken_with_compress_to_pubkey.rs is excluded by none and included by none
  • sdk-tests/sdk-token-test/tests/compress_and_close_cpi.rs is excluded by none and included by none
  • sdk-tests/sdk-token-test/tests/decompress_full_cpi.rs is excluded by none and included by none
  • sdk-tests/sdk-token-test/tests/pda_ctoken.rs is excluded by none and included by none
  • sdk-tests/sdk-token-test/tests/test_4_transfer2.rs is excluded by none and included by none
  • sdk-tests/sdk-token-test/tests/test_compress_full_and_close.rs is excluded by none and included by none
📒 Files selected for processing (31)
  • program-libs/compressed-account/src/instruction_data/traits.rs (1 hunks)
  • programs/compressed-token/program/src/mint_action/accounts.rs (1 hunks)
  • programs/compressed-token/program/src/mint_action/processor.rs (0 hunks)
  • sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (3 hunks)
  • sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/mod.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_to_compressed/instruction.rs (3 hunks)
  • sdk-libs/compressed-token-sdk/src/compressed_token/v2/update_compressed_mint/instruction.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/close.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/compressible.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/create.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/create_associated_token_account.rs (0 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/instruction.rs (0 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/mod.rs (0 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/mod.rs (2 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken.rs (0 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken_spl.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (4 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_spl_ctoken.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/error.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/lib.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/tests/create_associated_token_account.rs (3 hunks)
  • sdk-libs/token-client/src/actions/create_compressible_token_account.rs (2 hunks)
  • sdk-libs/token-client/src/actions/mint_action.rs (1 hunks)
  • sdk-libs/token-client/src/actions/transfer2/ctoken_to_spl.rs (1 hunks)
  • sdk-libs/token-client/src/actions/transfer2/spl_to_ctoken.rs (3 hunks)
  • sdk-libs/token-client/src/instructions/create_mint.rs (2 hunks)
  • sdk-libs/token-client/src/instructions/mint_action.rs (3 hunks)
💤 Files with no reviewable changes (5)
  • sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/mod.rs
  • programs/compressed-token/program/src/mint_action/processor.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/instruction.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_associated_token_account.rs
🧰 Additional context used
🧬 Code graph analysis (16)
sdk-libs/token-client/src/actions/transfer2/ctoken_to_spl.rs (1)
sdk-libs/compressed-token-sdk/src/token_pool.rs (1)
  • find_token_pool_pda_with_index (20-28)
sdk-libs/token-client/src/instructions/create_mint.rs (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs (2)
  • derive_compressed_mint_address (193-202)
  • find_spl_mint_address (212-217)
sdk-libs/token-client/src/actions/mint_action.rs (1)
sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (1)
  • derive_ctoken_ata (20-29)
sdk-libs/compressed-token-sdk/src/ctoken/create.rs (2)
sdk-libs/compressed-token-sdk/src/ctoken/compressible.rs (2)
  • new (33-39)
  • new (57-73)
sdk-libs/compressed-token-sdk/src/error.rs (3)
  • from (77-79)
  • from (83-85)
  • from (89-122)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken_spl.rs (3)
sdk-libs/compressed-token-sdk/src/error.rs (3)
  • from (77-79)
  • from (83-85)
  • from (89-122)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/account2.rs (2)
  • compress_ctoken (169-190)
  • decompress_spl (250-279)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/transfer2/account_metas.rs (1)
  • new_decompressed_accounts_only (33-46)
sdk-libs/token-client/src/actions/transfer2/spl_to_ctoken.rs (1)
sdk-libs/compressed-token-sdk/src/token_pool.rs (1)
  • find_token_pool_pda_with_index (20-28)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_to_compressed/instruction.rs (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
  • new (43-61)
sdk-libs/token-client/src/instructions/mint_action.rs (2)
sdk-libs/token-client/src/actions/mint_action.rs (1)
  • mint_action (24-59)
program-libs/ctoken-types/src/instructions/mint_action/mint_to_compressed.rs (2)
  • new (14-19)
  • new (30-35)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (2)
sdk-libs/token-client/src/actions/ctoken_transfer.rs (1)
  • transfer_ctoken (20-38)
sdk-libs/compressed-token-sdk/src/utils.rs (1)
  • is_ctoken_account (22-37)
sdk-libs/compressed-token-sdk/tests/create_associated_token_account.rs (2)
sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (1)
  • derive_ctoken_ata (20-29)
sdk-libs/compressed-token-sdk/src/ctoken/close.rs (1)
  • new (18-26)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/mod.rs (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
  • get_mint_action_instruction_account_metas_cpi_write (181-209)
sdk-libs/compressed-token-sdk/src/ctoken/mod.rs (2)
sdk-libs/sdk/src/compressible/close.rs (1)
  • close (6-40)
sdk-libs/token-client/src/actions/ctoken_transfer.rs (1)
  • transfer_ctoken (20-38)
sdk-libs/token-client/src/actions/create_compressible_token_account.rs (3)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
  • new (43-61)
sdk-libs/compressed-token-sdk/src/ctoken/close.rs (1)
  • new (18-26)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (1)
  • new (40-57)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
sdk-libs/token-client/src/actions/mint_action.rs (1)
  • mint_action (24-59)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
  • new_create_mint (22-40)
sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (4)
sdk-libs/compressed-token-sdk/src/ctoken/create.rs (6)
  • invoke (122-138)
  • new (24-38)
  • new (102-116)
  • instruction (40-90)
  • instruction (118-120)
  • from (160-178)
program-libs/compressed-account/src/instruction_data/traits.rs (6)
  • cpi_context (58-58)
  • data (26-34)
  • data (87-87)
  • data (108-108)
  • address (84-84)
  • address (105-105)
program-libs/ctoken-types/src/instructions/mint_action/builder.rs (2)
  • new_mint (44-63)
  • new_mint_write_to_cpi_context (65-84)
program-libs/compressed-account/src/pubkey.rs (1)
  • new_from_array (79-81)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: programs (system-cpi-test-v2-functional-account-infos, ["cargo-test-sbf -p system-cpi-v2-test -- ...
  • GitHub Check: programs (system-cpi-test-v2-functional-read-only, ["cargo-test-sbf -p system-cpi-v2-test -- func...
  • GitHub Check: programs (system-cpi-test, ["cargo-test-sbf -p system-cpi-test", "cargo test -p light-system-prog...
  • GitHub Check: programs (account-compression-and-registry, ["cargo-test-sbf -p account-compression-test", "cargo...
  • GitHub Check: Test batched-merkle-tree-simulate
  • GitHub Check: Test program-libs-slow
  • GitHub Check: Test program-libs-fast
  • GitHub Check: Forester e2e test
🔇 Additional comments (13)
program-libs/compressed-account/src/instruction_data/traits.rs (1)

30-32: Readability improvement: Good separation of concerns.

Adding a blank line between discriminator serialization and inputs serialization cleanly separates two distinct logical operations. This aligns well with Rust conventions and improves code clarity without affecting functionality.

sdk-libs/compressed-token-sdk/src/error.rs (1)

114-114: Error code reassignment verified—changes are sound.

The removed error variants (CreateMintDataRequired and CreateMintMustBeNone) are not referenced anywhere else in the codebase, confirming the removal is clean and complete. The error code reassignment for CpiContextRequired from 17026 to 17024 maintains sequential numbering and is properly isolated to the error mapping definition.

sdk-libs/token-client/src/actions/mint_action.rs (1)

101-112: Switch to ctoken::derive_ctoken_ata keeps behavior consistent and centralizes ATA derivation

Using derive_ctoken_ata from the ctoken module in this MintToCToken branch keeps the call site simple and aligns with the new SDK builders, while still deriving the ATA from the recipient pubkey and spl_mint_pda. No additional issues from this change.

sdk-libs/token-client/src/actions/transfer2/ctoken_to_spl.rs (1)

5-7: Updated TransferCtokenToSpl import matches the new public ctoken API

Pointing the import directly at ctoken::TransferCtokenToSpl (instead of via transfer_interface) matches the refactored SDK layout and leaves the transfer call site unchanged. Looks good.

sdk-libs/compressed-token-sdk/src/lib.rs (1)

14-15: Re‑exporting CompressedProof at the crate root is a reasonable API ergonomic

Surfacing CompressedProof here aligns with how other core types are re‑exported and makes it easier for downstream users to work with compressed proofs without depending on light_compressed_account directly. Just keep in mind this symbol is now part of your stable public surface for semver purposes.

sdk-libs/token-client/src/actions/transfer2/spl_to_ctoken.rs (1)

5-7: Renamed SPL→ctoken destination wiring looks consistent

The switch to ctoken::TransferSplToCtoken and the rename to destination_ctoken_account are applied consistently in the function signature and struct init; SPL source vs ctoken destination are now clearly distinguished with no behavior change.

Also applies to: 16-23, 36-47

sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs (1)

163-170: CPI-write meta-config update matches new MintActionMetaConfigCpiWrite shape

The updated MintActionMetaConfigCpiWrite literal (dropping mint_needs_to_sign and keeping mint_signer: Some(input.mint_signer)) lines up with the new struct definition and the fact that this path always has a mint signer. Continuing to delegate to get_mint_action_instruction_account_metas_cpi_write here is fine given the specialized CPI-write behavior.

sdk-libs/compressed-token-sdk/src/compressed_token/v2/update_compressed_mint/instruction.rs (1)

66-75: Update path’s meta-config wiring looks correct

MintActionMetaConfig::new(input.payer, input.authority, input.in_merkle_tree, input.in_output_queue, input.out_output_queue) matches the new signature (payer, authority, state tree, input queue, output queue), and switching to .to_account_metas() keeps account metas centralized with the rest of the mint_action flows. No issues here.

sdk-libs/token-client/src/instructions/create_mint.rs (1)

64-76: Unwrap on RPC proof is a legitimate panic risk; verify the versioning strategy

Your first concern about the .unwrap() is spot-on. The function already establishes a clean error handling pattern at line 88 with RpcError::CustomError(), so line 71's direct unwrap breaks that contract. If the indexer returns None (due to misconfiguration, network hiccup, or indexer glitch), you'll panic instead of propagating a typed error—exactly what you're flagging.

For the hardcoded version: 3: my search found no VERSION or CTOKEN_VERSION constants in the codebase. That doesn't mean one shouldn't exist, but it does mean the current approach warrants a design decision. Before committing the fix:

  • Check the Light Protocol token types architecture (light-ctoken-types) to understand versioning intent—is version truly immutable per implementation, or could it evolve?
  • If versioning should be dynamic, define a constant in the appropriate types module and reference it.
  • If version 3 is intentionally locked, add a comment explaining why (e.g., "Hardcoded for CreateCMint V3 specification").

The proof handling fix (converting unwrap to ok_or_else(...)) is the critical fix to implement immediately. The version approach is a secondary decision based on your protocol's versioning contract.

sdk-libs/compressed-token-sdk/tests/create_associated_token_account.rs (1)

1-102: Tests nicely cover the new ATA builder surface

The updated tests exercise:

  • Discriminator selection for regular vs idempotent variants.
  • Instruction data consistency between the two.
  • new_with_bump behavior, including idempotent mode.
  • Account count for the compressible configuration.

This gives good confidence in the CreateAssociatedTokenAccount API and its wire format; no issues spotted here.

sdk-libs/compressed-token-sdk/src/ctoken/transfer_spl_ctoken.rs (1)

43-78: The review comment's account mismatch claim is technically incorrect, but the underlying design concern is valid

After examining the code, the account order and count actually do align:

  • get_transfer2_instruction_account_metas() for decompressed_accounts_only=true builds metas in order: CPI_AUTHORITY_PDA, fee_payer, then the 6 packed_accounts (8 total)
  • invoke()'s account_infos slice is arranged identically: compressed_token_program_authority, payer, then the same 6 packed accounts (8 total)

The accounts match if and only if compressed_token_program_authority is correctly initialized to the CPI_AUTHORITY_PDA account. The code's comment already documents this dependency: "Account order must match instruction metas: cpi_authority_pda, fee_payer, packed_accounts..."

However, there is a real design issue: this constraint is implicit and never validated. The TransferSplToCtokenAccountInfos struct accepts compressed_token_program_authority as a free parameter without enforcing or documenting that it must be the CPI authority. If a caller passes the wrong account, the CPI will fail at runtime without a compile-time or clear validation error.

Consider:

  • Either explicitly derive/validate that compressed_token_program_authority must be CPI_AUTHORITY_PDA within the instruction building logic
  • Or document this constraint prominently in the struct and all call sites
  • Or remove the parameter from the struct and hardcode CPI_AUTHORITY_PDA directly

Likely an incorrect or invalid review comment.

sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken_spl.rs (1)

42-77: <!-- [scratchpad_start]
[task review_transfer_ctoken_spl verification FINAL]
Compared SPL→ctoken and ctoken→SPL structures and traced full meta path.

[CRITICAL FINDINGS]

  1. Both TransferSplToCtoken and TransferCtokenToSpl have identical structure:

    • Inner struct WITHOUT compressed_token_program_authority
    • AccountInfos wrapper WITH compressed_token_program_authority
    • invoke/invoke_signed prepend compressed_token_program_authority to account_infos
  2. Meta construction path is IDENTICAL for both:

    • packed_accounts (6 items): [mint, account, account, authority, pool, program]
    • Passed to new_decompressed_accounts_only(payer, packed_accounts)
    • get_transfer2_instruction_account_metas builds: [CPI_AUTHORITY_PDA, payer, ...packed_accounts]
  3. CRITICAL: CPI_AUTHORITY_PDA IS in the metas

    • Lines 110-113 of account_metas.rs push CPI_AUTHORITY_PDA for decompressed_accounts_only=true
    • This happens automatically, not via Transfer2Config parameter
    • The reviewer's claim that it's "not propagated" is WRONG
  4. account_infos ordering MATCHES metas ordering perfectly:

    • Instruction metas: [CPI_AUTHORITY_PDA, payer, mint, src/dst, authority, pool, spl_token_program]
    • account_infos: [compressed_token_program_authority, payer, mint, src/dst, authority, pool, spl_token_program]
    • The compressed_token_program_authority field IS the CPI_AUTHORITY_PDA
  5. Both directions (SPL→ctoken and ctoken→SPL) have IDENTICAL structure and comments

    • Comments explicitly state: "Account order must match instruction metas: cpi_authority_pda, fee_payer, packed_accounts..."
    • This shows intentional correct design

[conclusion]
The review comment is INCORRECT. The code is working as designed:

  • CPI authority IS in the metas (added by get_transfer2_instruction_account_metas)
  • account_infos ordering DOES match instruction metas
  • No mismatch exists
  • The helpers are safe to use

[done]
</scratchpad_end] -->

The review comment is incorrect; the code is actually correct.

Your implementation properly aligns account_infos with the instruction metas. The CPI_AUTHORITY_PDA is automatically added by get_transfer2_instruction_account_metas() when decompressed_accounts_only=true (line 110-113 of account_metas.rs), even though it's not explicitly passed through Transfer2Config. This matches your compressed_token_program_authority field placement and your explicit comment about ordering.

The meta construction path is:

  1. new_decompressed_accounts_only(payer, packed_accounts) sets cpi_context: None and decompressed_accounts_only: true
  2. get_transfer2_instruction_account_metas() sees decompressed_accounts_only=true and automatically pushes CPI_AUTHORITY_PDA first (readonly, not signer), then payer (writable, signer), then the 6 packed accounts
  3. Your invoke() correctly mirrors this: compressed_token_program_authority, then payer, then the packed accounts

Both your ctoken→SPL and SPL→ctoken paths use identical ordering logic and are consistent. The runtime will accept these CPIs because the keys and flags match the instruction metas.

sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (1)

25-52: CreateCMint parameter structs and address derivation helpers look sound

The CreateCMintParams / CreateCMintCpiWriteParams structs capture the expected knobs (decimals, version, authorities, root index, compression address, optional extensions) with a reasonable default of version 3, and the helper functions:

  • derive_compressed_mint_address(...)
  • derive_cmint_from_spl_mint(...)
  • find_spl_mint_address(...)

all follow the expected pattern of deriving addresses from the SPL mint (or mint seed), address tree, and COMPRESSED_TOKEN_PROGRAM_ID. Assuming these seeds match the on‑chain program’s convention, the derivations should be stable and predictable.

Also applies to: 156-200, 443-470

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: 4

♻️ Duplicate comments (4)
sdk-libs/compressed-token-sdk/src/ctoken/mod.rs (1)

31-77: Document invariants for SystemAccountInfos/SystemAccounts and versioned PDAs

SystemAccountInfos<'info> / SystemAccounts nicely reflect the fixed Light Protocol base accounts, and the new COMPRESSIBLE_CONFIG_V1 / RENT_SPONSOR constants make those PDAs explicit. The trade‑off is that:

  • The field order in SystemAccountInfos / SystemAccounts must stay in sync with CTokenDefaultAccounts and the order used by mint/transfer account‑meta builders, and
  • COMPRESSIBLE_CONFIG_V1 and RENT_SPONSOR are now baked‑in, network‑specific PDAs (v1).

It would help future maintainers if the invariants were documented, for example:

/// Base Light Protocol system accounts used by all ctoken instructions.
/// Field order must match `CTokenDefaultAccounts` and the account meta layout.
pub struct SystemAccountInfos<'info> { ... }

/// v1 global compressible config PDA; bump this and keep old constants around
/// if the on-chain config layout changes.
pub const COMPRESSIBLE_CONFIG_V1: Pubkey = /* ... */;

This mirrors an earlier nit about documenting these invariants and makes future upgrades less error‑prone.

Also applies to: 83-86, 114-120

sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs (2)

263-336: AccountInfo ordering for MintToCTokenInfos in CPI-context mode likely still mismatches to_account_metas

In MintToCTokenInfos::invoke{,_signed} you always push:

  1. Light system + authority + payer + Light base PDAs,
  2. Optional cpi_context_account,
  3. output_queue, state_tree, input_queue,
  4. Then all ctoken_accounts.

However, in the CPI-context path MintToCToken::instruction builds its metas via:

let meta_config = MintActionMetaConfig::new_cpi_context(
    &instruction_data,
    self.payer,
    self.params.mint_authority,
    cpi_context_pubkey,
)?;
let account_metas = meta_config.to_account_metas();

and MintActionMetaConfig::new_cpi_context initializes:

Ok(Self {
    fee_payer,
    authority,
    tree_pubkey: Pubkey::default(),
    output_queue: Pubkey::default(),
    mint_signer: None,
    input_queue: None,
    tokens_out_queue: None,
    cpi_context: Some(cpi_context_pubkey),
    ctoken_accounts: Vec::new(),
})

So in CPI mode the metas will contain just the base Light accounts + cpi_context, not the queues, and any ctoken_accounts are not coming from this config. Pushing queues (and potentially extra accounts) here risks InstructionError::AccountMismatch when the metas and AccountInfo slice diverge.

A safer layout for CPI-context calls is:

-        let mut account_infos = vec![
-            self.system_accounts.light_system_program,
-            self.authority, // authority
-            self.payer,     // fee_payer
-            self.system_accounts.cpi_authority_pda,
-            self.system_accounts.registered_program_pda,
-            self.system_accounts.account_compression_authority,
-            self.system_accounts.account_compression_program,
-            self.system_accounts.system_program,
-        ];
-
-        if let Some(cpi_context_account) = self.cpi_context_account {
-            account_infos.push(cpi_context_account);
-        }
-
-        account_infos.push(self.output_queue);
-        account_infos.push(self.state_tree);
-        account_infos.push(self.input_queue);
-        account_infos.extend(self.ctoken_accounts);
+        let mut account_infos = vec![
+            self.system_accounts.light_system_program,
+            self.authority, // authority
+            self.payer,     // fee_payer
+            self.system_accounts.cpi_authority_pda,
+            self.system_accounts.registered_program_pda,
+            self.system_accounts.account_compression_authority,
+            self.system_accounts.account_compression_program,
+            self.system_accounts.system_program,
+        ];
+
+        if let Some(cpi_context_account) = self.cpi_context_account {
+            account_infos.push(cpi_context_account);
+        }
+
+        // Only queues are used in the non-CPI path; in CPI-context mode
+        // the metas do not include them.
+        if self.cpi_context.is_none() {
+            account_infos.push(self.output_queue);
+            account_infos.push(self.state_tree);
+            account_infos.push(self.input_queue);
+        }
+
+        account_infos.extend(self.ctoken_accounts);

Apply the same pattern in invoke_signed. This mirrors how MintActionMetaConfig::to_account_metas distinguishes CPI vs non‑CPI modes and avoids reintroducing the mismatch that a previous review comment already highlighted.

#!/bin/bash
# Sanity-check that the number and order of metas from MintActionMetaConfig
# match the AccountInfo slice built in MintToCTokenInfos for both modes.

rg -n "impl MintActionMetaConfig" sdk-libs/compressed-token-sdk/src -C5
rg -n "to_account_metas" sdk-libs/compressed-token-sdk/src -C5
rg -n "MintToCTokenInfos" sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs -n -C5

Also applies to: 338-368


374-391: CPI-write helper still doesn’t supply the base accounts expected by get_mint_action_instruction_account_metas_cpi_write

get_mint_action_instruction_account_metas_cpi_write produces metas in this order (with mint_signer currently None):

  1. light_system_program (from CTokenDefaultAccounts),
  2. authority (mint signer / authority),
  3. fee_payer,
  4. cpi_authority_pda,
  5. cpi_context.

But MintToCTokenCpiWriteInfos::invoke_signed only supplies:

let mut account_infos = vec![self.payer, self.cpi_context_account];
account_infos.extend(self.ctoken_accounts);

This will immediately misalign metas vs accounts and trigger InstructionError::AccountMismatch at runtime.

You need MintToCTokenCpiWriteInfos to carry the same base accounts and feed them in the proper order, e.g.:

-pub struct MintToCTokenCpiWriteInfos<'info> {
-    pub payer: AccountInfo<'info>,
-    pub cpi_context_account: AccountInfo<'info>,
-    pub ctoken_accounts: Vec<AccountInfo<'info>>,
-    pub params: MintToCTokenCpiWriteParams,
-}
+pub struct MintToCTokenCpiWriteInfos<'info> {
+    /// Mint authority / instruction authority (matches params.mint_authority).
+    pub authority: AccountInfo<'info>,
+    /// Fee payer.
+    pub payer: AccountInfo<'info>,
+    /// Light system accounts (must align with CTokenDefaultAccounts).
+    pub system_accounts: crate::ctoken::SystemAccountInfos<'info>,
+    /// CPI context account.
+    pub cpi_context_account: AccountInfo<'info>,
+    /// Any additional ctoken accounts used by the CPI context.
+    pub ctoken_accounts: Vec<AccountInfo<'info>>,
+    pub params: MintToCTokenCpiWriteParams,
+}
@@
-    pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
-        let instruction = self.instruction()?;
-        let mut account_infos = vec![self.payer, self.cpi_context_account];
-        account_infos.extend(self.ctoken_accounts);
-        invoke_signed(&instruction, &account_infos, signer_seeds)
-    }
+    pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
+        let instruction = self.instruction()?;
+        // Must mirror get_mint_action_instruction_account_metas_cpi_write
+        let mut account_infos = vec![
+            self.system_accounts.light_system_program,
+            self.authority,
+            self.payer,
+            self.system_accounts.cpi_authority_pda,
+            self.cpi_context_account,
+        ];
+        account_infos.extend(self.ctoken_accounts);
+        invoke_signed(&instruction, &account_infos, signer_seeds)
+    }
@@
-impl<'info> From<&MintToCTokenCpiWriteInfos<'info>> for MintToCTokenCpiWrite {
+impl<'info> From<&MintToCTokenCpiWriteInfos<'info>> for MintToCTokenCpiWrite {
     fn from(account_infos: &MintToCTokenCpiWriteInfos<'info>) -> Self {
         Self {
             payer: *account_infos.payer.key,
             cpi_context_pubkey: *account_infos.cpi_context_account.key,
             ctoken_accounts: account_infos
                 .ctoken_accounts
                 .iter()
                 .map(|acc| *acc.key)
                 .collect(),
             params: account_infos.params.clone(),
         }
     }
 }

Call sites will need to be updated to supply authority and system_accounts, mirroring how MintToCTokenInfos is already structured.

This exact problem was flagged earlier; the current code regresses back to the broken layout.

#!/bin/bash
# Grep for MintToCTokenCpiWriteInfos usage and ensure all call sites
# can supply authority + system_accounts in the required order.
rg -n "MintToCTokenCpiWriteInfos" -C3
rg -n "get_mint_action_instruction_account_metas_cpi_write" sdk-libs/compressed-token-sdk/src -C5

Also applies to: 394-406

sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (1)

90-143: Fix account ordering mismatch between to_account_metas() and invoke() methods.

The current implementation has inconsistent account ordering when CPI context is present. In MintActionMetaConfig::to_account_metas() (sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs, lines 99–149), the optional cpi_context is inserted before output_queue and tree_pubkey. However, in CreateCMintAccountInfos::invoke() and invoke_signed() (sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs, lines 321–341 and 346–366), these accounts are pushed afterward.

When cpi_context is Some, the account vectors differ:

  • to_account_metas(): […system_program, cpi_context, output_queue, tree_pubkey]
  • invoke(): […system_program, output_queue, tree_pubkey, cpi_context]

This violates the stated invariant in both invoke() methods' comments ("Account order must match"). Reorder the accounts in invoke() and invoke_signed() to insert cpi_context before output_queue and tree_pubkey, matching to_account_metas() exactly.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6757675 and eef35f2.

⛔ Files ignored due to path filters (12)
  • .github/workflows/sdk-tests.yml is excluded by none and included by none
  • Cargo.lock is excluded by !**/*.lock and included by none
  • Cargo.toml is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/src/instruction_accounts.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/src/instructions/create_user_record_and_game_session.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/src/instructions/decompress_accounts_idempotent.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/tests/game_session_tests.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/tests/helpers.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/tests/idempotency_tests.rs is excluded by none and included by none
  • sdk-tests/sdk-compressible-test/tests/multi_account_tests.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/transfer_interface.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/test_create_cmint.rs is excluded by none and included by none
📒 Files selected for processing (6)
  • sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/mod.rs (2 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (7 hunks)
  • sdk-libs/compressed-token-sdk/src/error.rs (2 hunks)
  • sdk-libs/compressed-token-sdk/src/lib.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/decompress_context.rs : DecompressContext implementation should generate account accessor methods, implement PDA/token separation logic, and delegate token processing
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/decompress_context.rs : DecompressContext implementation should generate account accessor methods, implement PDA/token separation logic, and delegate token processing

Applied to files:

  • sdk-libs/compressed-token-sdk/src/lib.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/mod.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs
  • sdk-libs/compressed-token-sdk/src/error.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/*.rs : Module structure in Rust should follow the documented organization: mod.rs for module declarations, traits.rs for core trait implementations (HasCompressionInfo, CompressAs, Compressible), pack_unpack.rs for Pubkey compression and Pack/Unpack traits, variant_enum.rs for account variant enums, instructions.rs for instruction handlers, seed_providers.rs for PDA seed derivation, and decompress_context.rs for decompression trait implementations

Applied to files:

  • sdk-libs/compressed-token-sdk/src/lib.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/mod.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs
  • sdk-libs/compressed-token-sdk/src/error.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/pack_unpack.rs : Pack/Unpack trait implementations should compress Pubkey fields by converting them to u8 indices in generated PackedXxx structs for serialization efficiency

Applied to files:

  • sdk-libs/compressed-token-sdk/src/lib.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/mod.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/variant_enum.rs : CompressedAccountVariant enum generation should implement all required traits: Default, DataHasher, Size, Pack, and Unpack, along with a CompressedAccountData wrapper struct

Applied to files:

  • sdk-libs/compressed-token-sdk/src/lib.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/mod.rs
  • sdk-libs/compressed-token-sdk/src/error.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/instructions.rs : Compress instruction handler should be PDA-only, with ctokens compressed via registry; Decompress instruction handler should support full PDA + ctoken support

Applied to files:

  • sdk-libs/compressed-token-sdk/src/lib.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/mod.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/traits.rs : HasCompressionInfo trait should provide CompressionInfo field access; CompressAs trait should provide field-level compression control; Compressible trait should bundle Size + HasCompressionInfo + CompressAs

Applied to files:

  • sdk-libs/compressed-token-sdk/src/lib.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/seed_providers.rs : Seed providers should implement PDA seed provider functionality with CToken seed provider supporting both account and authority derivation, along with client-side seed functions for off-chain use

Applied to files:

  • sdk-libs/compressed-token-sdk/src/lib.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/mod.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs
🧬 Code graph analysis (3)
sdk-libs/compressed-token-sdk/src/ctoken/mod.rs (4)
sdk-libs/sdk/src/compressible/close.rs (1)
  • close (6-43)
sdk-libs/sdk/src/compressible/decompress_runtime.rs (1)
  • compressible (204-204)
sdk-libs/token-client/src/actions/ctoken_transfer.rs (1)
  • transfer_ctoken (20-38)
sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (1)
  • default (39-51)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (1)
sdk-libs/compressed-token-sdk/src/utils.rs (1)
  • is_ctoken_account (22-37)
sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs (1)
sdk-libs/compressed-token-sdk/src/error.rs (3)
  • from (85-87)
  • from (91-93)
  • from (97-134)
🪛 GitHub Actions: lint
sdk-libs/compressed-token-sdk/src/lib.rs

[error] 12-12: Diff in file detected during linting step: changes to 'pub use light_compressed_account::instruction_data::compressed_proof::CompressedProof' appear with a +/- context. Process exited with code 1. Command: nx run @lightprotocol/sdk-anchor-test:lint.

🔇 Additional comments (13)
sdk-libs/compressed-token-sdk/src/error.rs (1)

96-126: New SPL-interface-related error codes and mappings look consistent

The added variants (SplInterfaceRequired, IncompleteSplInterface, MissingMintAccount, MissingSplTokenProgram, MissingTokenPoolPda, MissingTokenPoolPdaBump) are all covered in the From<TokenSdkError> for u32 match, with contiguous codes and no gaps. This keeps the on‑chain encoding consistent with the rest of the error enum.

sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (3)

4-9: Use of typed account-info wrappers for transfer flows looks good

Importing the three account-info structs (TransferCtokenAccountInfos, TransferCtokenToSplAccountInfos, TransferSplToCtokenAccountInfos) and is_ctoken_account centralizes the transfer logic cleanly. This keeps the interface layer small and focused on routing.


11-27: SplInterface and TransferInterface shapes are sensible

Factoring SPL‑side state into SplInterface<'info> and holding it as an Option inside TransferInterface<'info> gives a clear separation between “pure ctoken” and “ctoken<->SPL bridge” paths. The amount placement and the new(...) constructor are straightforward and make the builder easy to use.

Also applies to: 29-54


130-138: Destination ctoken account naming matches the SPL→ctoken helpers

Renaming the field passed into TransferSplToCtokenAccountInfos as destination_ctoken_account improves clarity and matches the helper’s expected field names, which should help avoid accidental account swaps.

Also applies to: 199-207

sdk-libs/compressed-token-sdk/src/ctoken/mod.rs (1)

1-29: ctoken module re-export surface is cohesive

Pulling all instruction builders, params, and transfer interfaces into this ctoken module via pub use (close/create*/mint_to/transfer*) creates a clean, single import surface for downstream users and tests. The inclusion of the SPL bridge types (SplInterface, TransferInterface, TransferCtokenToSpl*, TransferSplToCtoken*) also makes the new flows discoverable.

sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs (3)

22-55: MintToCTokenParams and MintToCToken builder are well-structured

The params + builder split is clear:

  • MintToCTokenParams owns the mint inputs, actions, authority, and proof with a small ergonomic new + add_mint_to_action API.
  • MintToCToken::instruction correctly wires MintActionCompressedInstructionData (including proof and optional CPI context) into MintActionMetaConfig::{new,new_cpi_context} and defers to to_account_metas, handling Borsh IO errors via ProgramError::BorshIoError.

The overall shape is sound and keeps instruction construction logic localized.

Also applies to: 61-147


153-187: CPI-write params and builder logic are consistent with meta-config helper

MintToCTokenCpiWriteParams and MintToCTokenCpiWrite mirror the non‑CPI flow cleanly:

  • You validate the CPI context flags before building the instruction.
  • You intentionally omit a proof (None) in the CPI-write variant.
  • MintActionMetaConfigCpiWrite is filled consistently with fee_payer, authority, and cpi_context, and account metas are derived exclusively via get_mint_action_instruction_account_metas_cpi_write.

The control flow here looks correct; the remaining risk is in how the accompanying MintToCTokenCpiWriteInfos feeds AccountInfos to invoke_signed (see separate comment).

Also applies to: 192-257


338-368: Authority/mint_authority consistency check in TryFrom is a good guardrail

The TryFrom<&MintToCTokenInfos<'info>> for MintToCToken implementation verifies that params.mint_authority matches the authority account key and logs a human‑readable message before returning ProgramError::InvalidAccountData. The corresponding From<&MintToCTokenCpiWriteInfos<'info>> keeps the CPI-write builder free of AccountInfo concerns.

These conversions are a solid pattern for separating account validation from instruction construction.

Also applies to: 394-406

sdk-libs/compressed-token-sdk/src/lib.rs (1)

15-15: The CompressedProof re-export is correctly formatted; verify the actual CI error before making changes

After examining the codebase, the pub use statement at line 15 in sdk-libs/compressed-token-sdk/src/lib.rs is syntactically sound and follows standard Rust re-export patterns. The file has no uncommitted changes and the code matches project conventions.

The concern appears to stem from a reported CI lint error in the nx run @lightprotocol/sdk-anchor-test:lint step. However:

  • The nx command is a TypeScript/JavaScript monorepo tool, not available in the Rust environment we examined
  • The sdk-anchor-test directory is currently a scaffolding stub with no actual source files
  • The Rust code itself is already properly formatted with no outstanding diffs

Before re-running formatters (which may not resolve a TypeScript-layer issue), check your CI logs directly to confirm whether the error is still present and what it actually reports. If the error persists, it may be infrastructure or TypeScript-side configuration, not a Rust formatting problem.

sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (4)

321-369: Account ordering is correct but fragile.

The invoke() and invoke_signed() methods correctly assemble accounts in the order expected by MintActionMetaConfig::to_account_metas(). However, this manual array construction is fragile—if the meta generation logic changes, these will silently break at runtime with InstructionError::AccountMismatch.

Consider adding a compile-time or integration test that verifies the account ordering remains synchronized between the builder's instruction method and the account infos' invoke methods.

</comment_end>


372-397: LGTM: Authority validation is appropriate.

The TryFrom implementation correctly validates that the mint_authority parameter matches the provided authority account, preventing configuration errors that would cause runtime failures.

</comment_end>


417-430: LGTM: CPI write account ordering is now correct.

The invoke_signed() method now correctly supplies all six accounts expected by get_mint_action_instruction_account_metas_cpi_write() in the proper order:

  1. light_system_program
  2. mint_signer
  3. authority
  4. payer (fee_payer)
  5. cpi_authority_pda
  6. cpi_context

This resolves the critical issue flagged in past reviews where only three accounts were provided.

</comment_end>


461-488: LGTM: Helper functions provide clear address derivation utilities.

The three helper functions correctly implement address derivation for compressed mints:

  • derive_compressed_mint_address: Derives from a mint seed via PDA
  • derive_cmint_from_spl_mint: Direct derivation from SPL mint address
  • find_spl_mint_address: PDA lookup using the compressed mint seed

The implementations use the appropriate Light Protocol address derivation and Solana PDA functions.

</comment_end>

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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
sdk-libs/token-client/src/instructions/create_mint.rs (1)

5-87: Client create_compressed_mint_instruction correctly uses CreateCMint; consider avoiding unwrap() on the proof

The refactor to construct a CreateCMintParams and then call CreateCMint::new(...).instruction() looks good: you derive the compressed mint address and SPL mint PDA with the same helpers the SDK exposes, and you thread decimals, mint_authority, freeze_authority, and extensions through cleanly.

One thing to double‑check is the use of:

proof: rpc_result.proof.0.unwrap(),

If get_validity_proof ever returns a result where the inner proof is None (e.g., indexer lag, misconfiguration, or an unexpected RPC edge case), this will panic the client instead of returning an RpcError. To keep the API’s failure mode consistent, you could convert this into an error rather than a panic, for example:

-    let params = CreateCMintParams {
-        decimals,
-        address_merkle_tree_root_index,
-        mint_authority,
-        proof: rpc_result.proof.0.unwrap(),
+    let proof = rpc_result
+        .proof
+        .0
+        .ok_or_else(|| RpcError::CustomError("missing validity proof for compressed mint".into()))?;
+
+    let params = CreateCMintParams {
+        decimals,
+        address_merkle_tree_root_index,
+        mint_authority,
+        proof,
         compression_address: compressed_mint_address,
         mint: find_spl_mint_address(&mint_seed.pubkey()).0,
         freeze_authority,
         extensions,
     };

If the invariant really is “proof is always present,” using expect("...") with a clear message would still be preferable to a bare unwrap() for debugging.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eef35f2 and b5a194b.

⛔ Files ignored due to path filters (4)
  • sdk-tests/csdk-anchor-derived-test/src/lib.rs is excluded by none and included by none
  • sdk-tests/csdk-anchor-full-derived-test/src/lib.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/src/create_cmint.rs is excluded by none and included by none
  • sdk-tests/sdk-ctoken-test/tests/shared.rs is excluded by none and included by none
📒 Files selected for processing (6)
  • sdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (1 hunks)
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (7 hunks)
  • sdk-libs/compressed-token-sdk/src/error.rs (2 hunks)
  • sdk-libs/compressed-token-sdk/src/lib.rs (1 hunks)
  • sdk-libs/token-client/src/instructions/create_mint.rs (2 hunks)
🧰 Additional context used
🧠 Learnings (7)
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/decompress_context.rs : DecompressContext implementation should generate account accessor methods, implement PDA/token separation logic, and delegate token processing

Applied to files:

  • sdk-libs/compressed-token-sdk/src/lib.rs
  • sdk-libs/token-client/src/instructions/create_mint.rs
  • sdk-libs/compressed-token-sdk/src/error.rs
  • sdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/*.rs : Module structure in Rust should follow the documented organization: mod.rs for module declarations, traits.rs for core trait implementations (HasCompressionInfo, CompressAs, Compressible), pack_unpack.rs for Pubkey compression and Pack/Unpack traits, variant_enum.rs for account variant enums, instructions.rs for instruction handlers, seed_providers.rs for PDA seed derivation, and decompress_context.rs for decompression trait implementations

Applied to files:

  • sdk-libs/compressed-token-sdk/src/lib.rs
  • sdk-libs/token-client/src/instructions/create_mint.rs
  • sdk-libs/compressed-token-sdk/src/error.rs
  • sdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/pack_unpack.rs : Pack/Unpack trait implementations should compress Pubkey fields by converting them to u8 indices in generated PackedXxx structs for serialization efficiency

Applied to files:

  • sdk-libs/compressed-token-sdk/src/lib.rs
  • sdk-libs/compressed-token-sdk/src/error.rs
  • sdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/variant_enum.rs : CompressedAccountVariant enum generation should implement all required traits: Default, DataHasher, Size, Pack, and Unpack, along with a CompressedAccountData wrapper struct

Applied to files:

  • sdk-libs/compressed-token-sdk/src/lib.rs
  • sdk-libs/compressed-token-sdk/src/error.rs
  • sdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/instructions.rs : Compress instruction handler should be PDA-only, with ctokens compressed via registry; Decompress instruction handler should support full PDA + ctoken support

Applied to files:

  • sdk-libs/compressed-token-sdk/src/lib.rs
  • sdk-libs/token-client/src/instructions/create_mint.rs
  • sdk-libs/compressed-token-sdk/src/error.rs
  • sdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/traits.rs : HasCompressionInfo trait should provide CompressionInfo field access; CompressAs trait should provide field-level compression control; Compressible trait should bundle Size + HasCompressionInfo + CompressAs

Applied to files:

  • sdk-libs/compressed-token-sdk/src/lib.rs
  • sdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/seed_providers.rs : Seed providers should implement PDA seed provider functionality with CToken seed provider supporting both account and authority derivation, along with client-side seed functions for off-chain use

Applied to files:

  • sdk-libs/compressed-token-sdk/src/lib.rs
  • sdk-libs/compressed-token-sdk/src/error.rs
  • sdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs
  • sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
🧬 Code graph analysis (3)
sdk-libs/token-client/src/instructions/create_mint.rs (1)
sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (5)
  • derive_compressed_mint_address (447-456)
  • find_spl_mint_address (468-473)
  • new (49-65)
  • new (147-166)
  • new (192-204)
sdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rs (3)
sdk-libs/compressed-token-sdk/src/ctoken/compressible.rs (1)
  • compress_to_pubkey (41-44)
prover/client/src/helpers.rs (1)
  • b (35-35)
sdk-libs/sdk/src/compressible/decompress_runtime.rs (4)
  • compressible (204-204)
  • fee_payer (65-65)
  • ctoken_config (71-71)
  • ctoken_rent_sponsor (68-68)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (1)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken.rs (2)
  • invoke (27-31)
  • invoke_signed (33-37)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Test program-libs-slow
  • GitHub Check: Test batched-merkle-tree-simulate
  • GitHub Check: Test program-libs-fast
  • GitHub Check: programs (system-cpi-test, ["cargo-test-sbf -p system-cpi-test", "cargo test -p light-system-prog...
  • GitHub Check: programs (system-cpi-test-v2-functional-read-only, ["cargo-test-sbf -p system-cpi-v2-test -- func...
  • GitHub Check: programs (compressed-token-and-e2e, ["cargo-test-sbf -p compressed-token-test --test v1", "cargo-...
  • GitHub Check: programs (system-cpi-test-v2-functional-account-infos, ["cargo-test-sbf -p system-cpi-v2-test -- ...
  • GitHub Check: programs (account-compression-and-registry, ["cargo-test-sbf -p account-compression-test", "cargo...
  • GitHub Check: Forester e2e test
🔇 Additional comments (7)
sdk-libs/compressed-token-sdk/src/lib.rs (1)

16-16: LGTM—verification confirms the re-export is actively used and correctly justified.

The light_compressed_account dependency exists in Cargo.toml, and CompressedProof is actively used by the new instruction builders (confirmed in create_cmint.rs where it's imported at line 2 and used as a field type at line 30). This re-export appropriately consolidates the public API, allowing downstream consumers to access the type directly through the compressed-token-sdk without coupling to internal light_compressed_account paths.

sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (2)

30-54: Clean refactoring of constructor.

The addition of amount as a direct parameter and initialization of spl_interface to None provides a clear separation between basic transfer setup and optional SPL bridge configuration.


93-111: Error handling now correctly aligned.

The previous review flagged mismatches between documented and actual error variants. This has been properly addressed:

  • Lines 109–111 now correctly return SplInterfaceRequired when the SPL interface is missing for SPL<->ctoken transfers
  • Lines 95, 97 now correctly map is_ctoken_account errors to CannotDetermineAccountType

The documentation (lines 89–92) and implementation are now consistent.

Based on past review comments.

sdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rs (2)

153-153: Verify hardcoded pre_pay_num_epochs value.

The pre_pay_num_epochs is hardcoded to 2. This determines how many epochs of rent are prepaid when creating the decompressed token account.

Ensure this value is appropriate for all decompression scenarios, or consider making it configurable if different contexts require different prepayment strategies.


124-139: The bump extraction is architecturally guaranteed by the macro system—no fix required.

Your concern was well-intentioned, but verification shows the seed structure is not just an assumed pattern; it's enforced by the code generator. Every implementation of CTokenSeedProvider in sdk-libs/macros/src/compressible/seed_providers.rs follows the identical pattern: find_program_address() → extend the seed vector → seeds_vec.push(vec![bump]) as the final element. This happens across lines 177–181, 319–323, 391–396, 425–427, 464–466, and 478–481. The extraction logic at lines 124–139 correctly reverses this guaranteed structure using .last().and_then(|b| b.first().copied()), with safe None handling for edge cases.

There's no risk of alternative seed structures—the macro enforces consistency across all implementations. The code is correct and safe as written.

Optional enhancements worth considering:

  • Add a comment documenting that bump is appended by the seed provider macros (helps future maintainers)
  • Cross-validate derived PDAs in debug builds for extra confidence, though it's not necessary
sdk-libs/compressed-token-sdk/src/error.rs (1)

52-126: SPL interface error variants and codes are now coherent

The renamed variants (IncompleteSplInterface, SplInterfaceRequired, and the new Missing* cases) have matching, clear error messages and distinct u32 codes (17020–17028). The mapping covers every concrete variant exactly once before delegating to wrapped errors, so the public error surface is consistent and unambiguous.

sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (1)

388-473: CPI‑write AccountInfos ordering and address helpers are consistent

CreateCompressedMintCpiWriteInfos::invoke_signed now passes exactly the six AccountInfos documented in the comment (light system program, mint signer, authority, fee payer, CPI authority PDA, CPI context), in the same order that MintActionMetaConfigCpiWrite is expected to emit metas for. That aligns the client‑side slice with the meta layout and avoids the missing‑account / account‑mismatch issues that can easily plague CPI helpers.

The helper functions for deriving the compressed mint address and SPL mint PDA (derive_compressed_mint_address, derive_cmint_from_spl_mint, find_spl_mint_address) consistently use COMPRESSED_MINT_SEED and COMPRESSED_TOKEN_PROGRAM_ID, so address derivations should remain stable and predictable.

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