Skip to content

feat: opt ctoken #1844

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

feat: opt ctoken #1844

wants to merge 5 commits into from

Conversation

ananas-block
Copy link
Contributor

@ananas-block ananas-block commented Jun 28, 2025

Summary by CodeRabbit

  • New Features

    • Introduced support for creating and managing compressed mints, including the ability to create compressed mint accounts and link them to Token-2022 SPL mints.
    • Enabled minting tokens to compressed accounts with cryptographic proof validation.
    • Added the capability to decompress compressed mints and synchronize supply with SPL token pools.
  • Bug Fixes

    • Improved collision resistance and authority uniqueness in compressed mint hashing.
  • Tests

    • Added comprehensive end-to-end tests for the compressed mint lifecycle, including creation, minting, SPL mint linkage, and decompression scenarios.
  • Documentation

    • Enhanced inline documentation and comments for new features and account requirements.
  • Chores

    • Introduced new error codes for improved error handling and reporting.

Copy link
Contributor

coderabbitai bot commented Jun 28, 2025

Walkthrough

This update introduces comprehensive support for compressed mints in the compressed token program. It adds new instructions and processing logic for creating compressed mints, minting tokens to compressed accounts, and creating corresponding SPL mints. The changes include new data structures, hashing logic, CPI serialization, and extensive tests covering the compressed mint lifecycle.

Changes

File(s) Change Summary
program-tests/compressed-token-test/tests/test.rs Adds an asynchronous test function for end-to-end validation of the compressed mint lifecycle, including creation, minting, SPL mint creation, and verification steps.
programs/compressed-token/src/constants.rs Introduces the COMPRESSED_MINT_DISCRIMINATOR constant for identifying compressed mint accounts.
programs/compressed-token/src/create_mint.rs Adds the CompressedMint struct with serialization, deserialization, and Poseidon hashing logic, along with tests for hashing correctness and collision resistance.
programs/compressed-token/src/instructions/create_compressed_mint.rs Introduces the CreateCompressedMintInstruction struct, defining accounts and constraints for creating compressed mints via Anchor.
programs/compressed-token/src/instructions/create_spl_mint.rs Adds the CreateSplMintInstruction struct for creating SPL mints and token pools linked to compressed mints, specifying all required accounts and constraints.
programs/compressed-token/src/instructions/mod.rs Adds and publicly re-exports the new create_compressed_mint and create_spl_mint instruction modules.
programs/compressed-token/src/lib.rs Integrates new modules and re-exports, introduces three new public instructions (create_compressed_mint, mint_to_compressed, create_spl_mint), adds error codes, and updates function signatures for minting logic.
programs/compressed-token/src/process_create_compressed_mint.rs Implements the logic for creating compressed mint accounts, including PDA derivation, struct serialization, hashing, CPI preparation, and invocation. Includes a test for verifying instruction data construction.
programs/compressed-token/src/process_create_spl_mint.rs Implements the logic for creating and initializing SPL mints and token pools from compressed mints, updating the compressed mint state, and performing associated CPI calls.
programs/compressed-token/src/process_mint.rs Adds support for minting to compressed accounts with new data structures, serialization logic, and CPI invocation adjustments. Updates the main mint processing function to handle compressed mint inputs and proofs, and adds corresponding tests.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Program
    participant LightSystem
    participant AccountCompression
    participant Token2022

    User->>Program: create_compressed_mint(params, proof)
    Program->>LightSystem: CPI to create compressed mint account
    LightSystem->>AccountCompression: Validate and store compressed account
    LightSystem-->>Program: Success

    User->>Program: mint_to_compressed(params, compressed_mint_inputs)
    Program->>LightSystem: CPI to mint tokens to compressed accounts
    LightSystem->>AccountCompression: Update compressed accounts
    LightSystem-->>Program: Success

    User->>Program: create_spl_mint(params, compressed_mint_inputs)
    Program->>Token2022: Create SPL mint account
    Program->>Token2022: Initialize mint and token pool
    Program->>LightSystem: CPI to mark compressed mint as decompressed
    LightSystem-->>Program: Success
Loading

Possibly related PRs

  • Lightprotocol/light-protocol#1802: Refactors CPI invocation and instruction data serialization for compressed mint creation, closely related to the new compressed mint and SPL mint creation logic introduced here.

Suggested reviewers

  • sergeytimoshin
  • SwenSchaeferjohann

Poem

In the meadow of mints, a new sprout appears,
Compressed and compact, it conquers old fears.
With hashes and proofs, it grows ever bright,
Now SPL joins in, what a marvelous sight!
Tokens leap lightly, as rabbits in spring—
On-chain and compressed, let the new era begin!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@ananas-block ananas-block changed the title feat: opt ctoken mint feat: opt ctoken Jun 30, 2025
@ananas-block ananas-block marked this pull request as ready for review June 30, 2025 15:29
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: 9

🧹 Nitpick comments (7)
programs/compressed-token/src/instructions/create_spl_mint.rs (2)

19-19: Add CHECK comment for mint_signer

The mint_signer account should have a CHECK comment explaining its validation or usage, consistent with other unchecked accounts in this struct.

+    /// CHECK: Used for PDA derivation
     pub mint_signer: UncheckedAccount<'info>,

49-49: Track the TODO for account packing optimization

Consider creating an issue to track this optimization opportunity.

Would you like me to create an issue to track the account packing optimization?

programs/compressed-token/src/process_create_spl_mint.rs (1)

28-28: Remove unused parameter

The _token_pool_bump parameter is not used in the function.

-    _token_pool_bump: u8,
program-tests/compressed-token-test/tests/test.rs (1)

6547-6552: Consider implementing the decompression test or tracking it as a TODO.

The decompression test is skipped because the tokens were minted to a pubkey rather than a keypair that can sign. This leaves an important part of the compressed mint lifecycle untested.

Would you like me to help implement a complete decompression test by either:

  1. Modifying the test to mint tokens to a keypair that can sign for decompression
  2. Creating a separate test specifically for decompression functionality
  3. Opening an issue to track this missing test coverage?
programs/compressed-token/src/create_mint.rs (1)

8-9: Address TODO: Consider adding is_native_compressed field.

The TODO suggests adding an is_native_compressed field to track sync state with SPL mint. This seems important for maintaining consistency between compressed and SPL representations. Please resolve this design decision.

Would you like me to help implement the is_native_compressed field and update the related logic?

programs/compressed-token/src/lib.rs (1)

120-120: Consider using a simpler import path.

The fully qualified path instructions::create_token_pool::assert_mint_extensions seems verbose. If there's no naming conflict, consider importing the function directly or using a shorter path.

programs/compressed-token/src/process_mint.rs (1)

262-263: Address TODO: Consider optimizing hash computation.

The TODO suggests using hashed inputs for efficiency. This could improve performance by avoiding redundant hashing operations.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ef0dd04 and 72c805f.

📒 Files selected for processing (10)
  • program-tests/compressed-token-test/tests/test.rs (2 hunks)
  • programs/compressed-token/src/constants.rs (1 hunks)
  • programs/compressed-token/src/create_mint.rs (1 hunks)
  • programs/compressed-token/src/instructions/create_compressed_mint.rs (1 hunks)
  • programs/compressed-token/src/instructions/create_spl_mint.rs (1 hunks)
  • programs/compressed-token/src/instructions/mod.rs (1 hunks)
  • programs/compressed-token/src/lib.rs (5 hunks)
  • programs/compressed-token/src/process_create_compressed_mint.rs (1 hunks)
  • programs/compressed-token/src/process_create_spl_mint.rs (1 hunks)
  • programs/compressed-token/src/process_mint.rs (16 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
programs/compressed-token/src/instructions/mod.rs (1)
programs/compressed-token/src/lib.rs (5)
  • create_compressed_mint (50-68)
  • create_spl_mint (95-111)
  • freeze (251-257)
  • freeze (256-256)
  • freeze (266-266)
programs/compressed-token/src/process_create_spl_mint.rs (5)
js/stateless.js/src/state/compressed-account.ts (2)
  • CompressedAccount (29-51)
  • PackedCompressedAccountWithMerkleContext (204-221)
js/stateless.js/src/state/types.ts (3)
  • CompressedAccountData (199-212)
  • OutputCompressedAccountWithPackedContext (170-173)
  • InstructionDataInvokeCpi (311-345)
js/compressed-token/src/constants.ts (1)
  • POOL_SEED (2-2)
programs/compressed-token/src/lib.rs (1)
  • create_spl_mint (95-111)
programs/compressed-token/src/process_transfer.rs (2)
  • process_transfer (39-179)
  • get_cpi_signer_seeds (379-383)
program-tests/compressed-token-test/tests/test.rs (8)
program-tests/utils/src/e2e_test_env.rs (3)
  • rpc (389-390)
  • new (346-434)
  • accounts (2510-2523)
sdk-libs/program-test/src/program_test/light_program_test.rs (1)
  • new (49-132)
program-libs/compressed-account/src/address.rs (2)
  • derive_address (30-41)
  • accounts (163-170)
programs/compressed-token/src/process_transfer.rs (2)
  • process_transfer (39-179)
  • get_cpi_authority_pda (718-720)
programs/system/src/utils.rs (3)
  • get_cpi_authority_pda (15-17)
  • get_registered_program_pda (11-13)
  • get_sol_pool_pda (19-21)
programs/compressed-token/src/instructions/transfer.rs (2)
  • get_registered_program_pda (45-47)
  • get_sol_pool_pda (65-67)
program-tests/utils/src/spl.rs (2)
  • create_token_pool (231-259)
  • create_token_2022_account (436-489)
programs/compressed-token/src/instructions/create_token_pool.rs (1)
  • find_token_pool_pda_with_index (45-53)
⏰ Context from checks skipped due to timeout of 90000ms (25)
  • GitHub Check: test-double-registration
  • GitHub Check: test-e2e
  • GitHub Check: test-address-batched
  • GitHub Check: test-state-batched
  • GitHub Check: test-state-photon-batched
  • GitHub Check: test-2-foresters
  • GitHub Check: Test batched-merkle-tree-simulate
  • GitHub Check: Test concurrent-merkle-tree
  • GitHub Check: Test program-libs-slow
  • GitHub Check: Test sdk-libs
  • GitHub Check: Test program-libs-fast
  • GitHub Check: system-programs (system-cpi-test-v2-other, ["cargo-test-sbf -p system-cpi-v2-test -- --skip funct...
  • GitHub Check: system-programs (system-cpi-test-v2-functional, ["cargo-test-sbf -p system-cpi-v2-test -- functio...
  • GitHub Check: system-programs (random-e2e-test, ["cargo-test-sbf -p e2e-test"])
  • GitHub Check: cli-v1
  • GitHub Check: cli-v2
  • GitHub Check: system-programs (system-cpi-test-v2-event, ["cargo-test-sbf -p system-cpi-v2-test -- event::parse"])
  • GitHub Check: lint
  • GitHub Check: system-programs (account-compression, ["cargo-test-sbf -p account-compression-test"])
  • GitHub Check: system-programs (light-system-program, ["cargo-test-sbf -p system-test"])
  • GitHub Check: stateless-js-v1
  • GitHub Check: system-programs (light-registry, ["cargo-test-sbf -p registry-test"])
  • GitHub Check: stateless-js-v2
  • GitHub Check: system-programs (light-compressed-token, ["cargo-test-sbf -p compressed-token-test"])
  • GitHub Check: system-programs (system-cpi-test, ["cargo-test-sbf -p system-cpi-test"])
🔇 Additional comments (6)
programs/compressed-token/src/constants.rs (1)

1-2: LGTM!

The new discriminator constant follows the established pattern and is correctly defined as 1 in little-endian format.

programs/compressed-token/src/instructions/mod.rs (1)

2-3: LGTM!

The new instruction modules are properly declared and re-exported following the established pattern.

Also applies to: 10-11

programs/compressed-token/src/instructions/create_compressed_mint.rs (1)

1-48: LGTM!

The instruction struct is well-designed with appropriate account types and validation annotations. The CHECK comments correctly indicate external validation by the light-system-program.

program-tests/compressed-token-test/tests/test.rs (1)

6103-6562: LGTM! Comprehensive test for compressed mint lifecycle.

The test thoroughly validates the compressed mint creation, minting to compressed accounts, and SPL mint creation flow. The test structure is clear and well-documented.

programs/compressed-token/src/process_create_compressed_mint.rs (2)

93-95: Verify the hardcoded indices are intentional.

The address_merkle_tree_account_index and address_queue_account_index are hardcoded to 0. Ensure this is the intended behavior and consider making them configurable if needed.


120-120: Verify merkle_tree_index value of 1 is correct.

The merkle_tree_index is hardcoded to 1, but typically indices start at 0. Please verify this is the correct value for the first output account in the merkle tree.

Comment on lines +50 to +62
/// Output queue account where compressed mint will be stored
/// CHECK: Validated by light-system-program
#[account(mut)]
pub in_output_queue: AccountInfo<'info>,
/// Output queue account where compressed mint will be stored
/// CHECK: Validated by light-system-program
#[account(mut)]
pub in_merkle_tree: AccountInfo<'info>,
/// Output queue account where compressed mint will be stored
/// CHECK: Validated by light-system-program
#[account(mut)]
pub out_output_queue: AccountInfo<'info>,
}
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

Fix misleading CHECK comments

The CHECK comments for these accounts are incorrect. The in_merkle_tree account is not an output queue.

-    /// Output queue account where compressed mint will be stored
+    /// Input output queue for compressed account updates
     /// CHECK: Validated by light-system-program
     #[account(mut)]
     pub in_output_queue: AccountInfo<'info>,
-    /// Output queue account where compressed mint will be stored
+    /// Input merkle tree for compressed account verification
     /// CHECK: Validated by light-system-program
     #[account(mut)]
     pub in_merkle_tree: AccountInfo<'info>,
-    /// Output queue account where compressed mint will be stored
+    /// Output queue for updated compressed mint
     /// CHECK: Validated by light-system-program
     #[account(mut)]
     pub out_output_queue: AccountInfo<'info>,
📝 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
/// Output queue account where compressed mint will be stored
/// CHECK: Validated by light-system-program
#[account(mut)]
pub in_output_queue: AccountInfo<'info>,
/// Output queue account where compressed mint will be stored
/// CHECK: Validated by light-system-program
#[account(mut)]
pub in_merkle_tree: AccountInfo<'info>,
/// Output queue account where compressed mint will be stored
/// CHECK: Validated by light-system-program
#[account(mut)]
pub out_output_queue: AccountInfo<'info>,
}
/// Input output queue for compressed account updates
/// CHECK: Validated by light-system-program
#[account(mut)]
pub in_output_queue: AccountInfo<'info>,
/// Input merkle tree for compressed account verification
/// CHECK: Validated by light-system-program
#[account(mut)]
pub in_merkle_tree: AccountInfo<'info>,
/// Output queue for updated compressed mint
/// CHECK: Validated by light-system-program
#[account(mut)]
pub out_output_queue: AccountInfo<'info>,
}
🤖 Prompt for AI Agents
In programs/compressed-token/src/instructions/create_spl_mint.rs between lines
50 and 62, the CHECK comments incorrectly describe the in_merkle_tree account as
an output queue. Update the CHECK comment for in_merkle_tree to accurately
reflect its purpose, removing the misleading reference to output queue and
specifying that it is validated by the light-system-program or the correct
validation context.

Comment on lines +89 to +97
let mut updated_compressed_mint = CompressedMint {
spl_mint: compressed_mint_inputs.compressed_mint_input.spl_mint,
supply: compressed_mint_inputs.compressed_mint_input.supply,
decimals,
is_decompressed: false, // Mark as decompressed
mint_authority: Some(mint_authority),
freeze_authority,
num_extensions: compressed_mint_inputs.compressed_mint_input.num_extensions,
};
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

Fix incorrect is_decompressed value

The comment says "Mark as decompressed" but the code sets is_decompressed: false. This appears to be a bug since the value is correctly set to true later on line 124.

         spl_mint: compressed_mint_inputs.compressed_mint_input.spl_mint,
         supply: compressed_mint_inputs.compressed_mint_input.supply,
         decimals,
-        is_decompressed: false, // Mark as decompressed
+        is_decompressed: false, // Initial value before update
         mint_authority: Some(mint_authority),
         freeze_authority,
         num_extensions: compressed_mint_inputs.compressed_mint_input.num_extensions,
📝 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
let mut updated_compressed_mint = CompressedMint {
spl_mint: compressed_mint_inputs.compressed_mint_input.spl_mint,
supply: compressed_mint_inputs.compressed_mint_input.supply,
decimals,
is_decompressed: false, // Mark as decompressed
mint_authority: Some(mint_authority),
freeze_authority,
num_extensions: compressed_mint_inputs.compressed_mint_input.num_extensions,
};
let mut updated_compressed_mint = CompressedMint {
spl_mint: compressed_mint_inputs.compressed_mint_input.spl_mint,
supply: compressed_mint_inputs.compressed_mint_input.supply,
decimals,
is_decompressed: false, // Initial value before update
mint_authority: Some(mint_authority),
freeze_authority,
num_extensions: compressed_mint_inputs.compressed_mint_input.num_extensions,
};
🤖 Prompt for AI Agents
In programs/compressed-token/src/process_create_spl_mint.rs around lines 89 to
97, the field is_decompressed is incorrectly set to false despite the comment
saying "Mark as decompressed." Change is_decompressed to true here to correctly
reflect the decompressed state, matching the intended logic and consistency with
line 124.

fn create_token_pool_account_manual<'info>(
ctx: &Context<'_, '_, '_, 'info, CreateSplMintInstruction<'info>>,
) -> Result<()> {
let token_account_size = 165; // Size of Token account
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Consider using constants for account sizes

Hardcoded account sizes (165 for token account, 82 for mint account) could break if the account structures change. Consider using constants or deriving sizes programmatically.

Also applies to: 303-303


🏁 Script executed:

#!/bin/bash
# Description: Check if these account sizes are defined as constants elsewhere in the codebase

# Search for token account size constants
rg -A 2 "token.*account.*size|TOKEN.*SIZE" --type rust

# Search for mint account size constants  
rg -A 2 "mint.*account.*size|MINT.*SIZE" --type rust

# Check Token-2022 program for size definitions
fd -e rs | xargs rg "165|82" -B 2 -A 2

Length of output: 265323


Replace hardcoded SPL account sizes with official constants

Hardcoding 165 and 82 risks breakage if the SPL Token account layouts evolve. Use the LEN constants from spl_token::state instead:

• programs/compressed-token/src/process_create_spl_mint.rs, line 231
Replace
let token_account_size = 165; // Size of Token account
With
let token_account_size = spl_token::state::Account::LEN;

• programs/compressed-token/src/process_create_spl_mint.rs, line 303
Replace
let mint_account_size = 82; // Size of Token-2022 Mint account
With
let mint_account_size = spl_token::state::Mint::LEN;

Diff example:

- let token_account_size = 165; // Size of Token account
+ let token_account_size = spl_token::state::Account::LEN;

- let mint_account_size = 82; // Size of Token-2022 Mint account
+ let mint_account_size = spl_token::state::Mint::LEN;

This ensures your code always matches the on-chain account definitions.

📝 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
let token_account_size = 165; // Size of Token account
// replace at line 231
let token_account_size = spl_token::state::Account::LEN;
// ...
// replace at line 303
let mint_account_size = spl_token::state::Mint::LEN;
🤖 Prompt for AI Agents
In programs/compressed-token/src/process_create_spl_mint.rs at line 231, replace
the hardcoded token account size value 165 with the official constant
spl_token::state::Account::LEN. Similarly, at line 303, replace the hardcoded
mint account size 82 with spl_token::state::Mint::LEN. This ensures the code
uses the authoritative SPL Token account size constants and remains compatible
with any future changes.

Comment on lines +6285 to +6286
token_pool_pda: Pubkey::new_unique(), // No token pool for pure compressed mint
token_program: spl_token::ID, // No token program for pure compressed mint
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

Fix incorrect token pool PDA setup for pure compressed mints.

The token pool PDA is set to a random pubkey (Pubkey::new_unique()) which appears incorrect. For pure compressed mints without an SPL mint, this should either be a proper PDA or handled differently. Additionally, the comment on line 6286 says "No token program for pure compressed mint" but still sets spl_token::ID.

Consider using a deterministic PDA or clarifying the intended behavior for pure compressed mints:

-        token_pool_pda: Pubkey::new_unique(), // No token pool for pure compressed mint
-        token_program: spl_token::ID, // No token program for pure compressed mint
+        token_pool_pda: Pubkey::default(), // Use default pubkey for pure compressed mint
+        token_program: spl_token::ID, // Required for account structure validation
🤖 Prompt for AI Agents
In program-tests/compressed-token-test/tests/test.rs around lines 6285 to 6286,
the token_pool_pda is incorrectly set to a random Pubkey using
Pubkey::new_unique(), which is not appropriate for pure compressed mints.
Replace this with a deterministic PDA derived from the mint or relevant seeds to
correctly represent the token pool. Also, since the comment states there is no
token program for pure compressed mints, remove or adjust the token_program
field to reflect this, either by setting it to None or an appropriate value
indicating no SPL token program is used.

],
&crate::ID,
)
.map_err(|_| crate::ErrorCode::InvalidTokenPoolPda)?;
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

Use appropriate error code for mint PDA creation failure.

The error code InvalidTokenPoolPda is misleading when the mint PDA creation fails. Consider using InvalidMintPda instead.

-    .map_err(|_| crate::ErrorCode::InvalidTokenPoolPda)?;
+    .map_err(|_| crate::ErrorCode::InvalidMintPda)?;
📝 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
.map_err(|_| crate::ErrorCode::InvalidTokenPoolPda)?;
.map_err(|_| crate::ErrorCode::InvalidMintPda)?;
🤖 Prompt for AI Agents
In programs/compressed-token/src/process_create_compressed_mint.rs at line 153,
the error code used for mint PDA creation failure is incorrectly set to
InvalidTokenPoolPda. Change this error code to InvalidMintPda to accurately
reflect the mint PDA creation failure.


let seeds = get_cpi_signer_seeds();
let mut inputs = Vec::new();
InstructionDataInvokeCpi::serialize(&inputs_struct, &mut inputs).unwrap();
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

Replace unwrap() with proper error handling.

Using unwrap() can cause the program to panic. Use proper error handling to avoid panics in production code.

-    InstructionDataInvokeCpi::serialize(&inputs_struct, &mut inputs).unwrap();
+    InstructionDataInvokeCpi::serialize(&inputs_struct, &mut inputs)?;
📝 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
InstructionDataInvokeCpi::serialize(&inputs_struct, &mut inputs).unwrap();
InstructionDataInvokeCpi::serialize(&inputs_struct, &mut inputs)?;
🤖 Prompt for AI Agents
In programs/compressed-token/src/process_create_compressed_mint.rs at line 26,
replace the use of unwrap() on the result of InstructionDataInvokeCpi::serialize
with proper error handling. Instead of calling unwrap(), handle the Result by
using a match statement or the ? operator to propagate the error, ensuring the
program does not panic and handles serialization failures gracefully.

// Not necessary.
// /// Is `true` if this structure has been initialized
// pub is_initialized: bool,
pub num_extensions: u8, // TODO: check again how token22 does it
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Address TODO: Verify token22 extension handling.

The TODO indicates uncertainty about how Token-2022 handles extensions. This should be verified to ensure compatibility.


🌐 Web query:

How does Token-2022 handle extensions and what is the proper way to count num_extensions?

💡 Result:

In the Token-2022 program, extensions are additional features that can be enabled on token mints and accounts to enhance their functionality. These extensions are optional and can be added during the initialization of a mint or token account. Each extension introduces specific state variables, and the total number of extensions enabled on a mint or account is tracked by the num_extensions field.

Understanding num_extensions:

The num_extensions field indicates the number of extensions currently enabled on a mint or token account. This field is crucial for correctly unpacking and interpreting the account data, as the presence of extensions affects the account's data structure.

Proper Way to Count num_extensions:

To accurately determine the number of extensions enabled on a mint or token account, you should unpack the account data using the StateWithExtensions structure provided by the spl-token-2022 library. This structure allows you to deserialize the base state of the mint or account and access the extensions in a way that accounts for the variable length of the extensions.

Here's how you can do this in Rust:

use spl_token_2022::{extension::StateWithExtensions, state::Mint, state::Account};

fn get_num_extensions_mint(account_data: &[u8]) -> usize {
    let mint_state = StateWithExtensions::<Mint>::unpack(account_data).unwrap();
    mint_state.get_extension_types().unwrap().len()
}

fn get_num_extensions_account(account_data: &[u8]) -> usize {
    let account_state = StateWithExtensions::<Account>::unpack(account_data).unwrap();
    account_state.get_extension_types().unwrap().len()
}

In this code:

  • StateWithExtensions::<Mint>::unpack(account_data) unpacks the mint account data, allowing access to both the base state and the extensions.

  • get_extension_types() retrieves the types of extensions enabled on the mint.

  • len() returns the number of extensions.

By using this approach, you can accurately determine the number of extensions enabled on a mint or token account, ensuring proper handling and interpretation of the account data.

For more detailed information on Token-2022 extensions and their usage, refer to the Solana Program Library's Extension Guide. (spl.solana.com)

Citations:


Implement accurate Token-2022 extension counting

The num_extensions field should reflect the actual number of enabled extensions on a mint, not a hard-coded placeholder. Use the StateWithExtensions helper in spl-token-2022 to deserialize the mint and count its extensions.

– In programs/compressed-token/src/create_mint.rs at the num_extensions declaration (line 32):

  1. Remove the // TODO… comment.
  2. When initializing the mint, unpack and count its extensions:
    use spl_token_2022::{extension::StateWithExtensions, state::Mint};
    
    // after loading `account_data: &[u8]` for the new mint…
    let mint_state = StateWithExtensions::<Mint>::unpack(account_data)
        .map_err(|_| ProgramError::InvalidAccountData)?;
    let num_extensions = mint_state
        .get_extension_types()
        .map_err(|_| ProgramError::InvalidAccountData)?
        .len() as u8;
    
    // assign to your struct:
    YourMintConfig { num_extensions, /* … */ }

This ensures num_extensions always matches the actual extensions present.

🤖 Prompt for AI Agents
In programs/compressed-token/src/create_mint.rs at line 32, replace the
hard-coded num_extensions field and remove the TODO comment. Instead, when
initializing the mint, use spl_token_2022's StateWithExtensions to unpack the
mint data and count the actual enabled extensions. Import StateWithExtensions
and Mint, unpack the mint from the account data, retrieve the extension types,
count them, and assign this count to num_extensions to ensure it accurately
reflects the mint's extensions.

Comment on lines +96 to +100
let option_compressed_mint_inputs = if compressed_mint_inputs.is_some() {
356
} else {
0
};
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

Replace hardcoded size with precise calculation.

The hardcoded value of 356 bytes for option_compressed_mint_inputs is fragile and could lead to memory allocation errors if the data structure size changes. Calculate the exact size based on the actual data structures.

Would you like me to help calculate the exact size based on the CompressedMintInputs structure?

Also applies to: 121-121

🤖 Prompt for AI Agents
In programs/compressed-token/src/process_mint.rs at lines 96 to 100 and line
121, replace the hardcoded size value 356 for option_compressed_mint_inputs with
a precise calculation based on the actual size of the CompressedMintInputs
structure. Use Rust's std::mem::size_of_val or size_of to dynamically compute
the size of the data structure instance or type, ensuring the size reflects any
changes in the structure and prevents memory allocation errors.

Comment on lines +530 to +680
// msg!(
// "compressed_inputs.output_merkle_tree_index {}",
// compressed_inputs.output_merkle_tree_index
// );

// Ok((input_compressed_account, output_compressed_mint_account))
// }

// #[cfg(target_os = "solana")]
// #[inline(never)]
// pub fn cpi_execute_compressed_transaction_mint_to_with_inputs<'info>(
// ctx: &Context<'_, '_, '_, 'info, MintToInstruction<'info>>,
// input_compressed_accounts: Vec<PackedCompressedAccountWithMerkleContext>,
// output_compressed_accounts: Vec<OutputCompressedAccountWithPackedContext>,
// proof: Option<CompressedProof>,
// inputs: &mut Vec<u8>,
// pre_compressed_accounts_pos: usize,
// ) -> Result<()> {
// bench_sbf_start!("tm_cpi_mint_update");

// let signer_seeds = get_cpi_signer_seeds();

// // Serialize CPI instruction data with inputs
// serialize_mint_to_cpi_instruction_data_with_inputs(
// inputs,
// &input_compressed_accounts,
// &output_compressed_accounts,
// proof,
// );

// GLOBAL_ALLOCATOR.free_heap(pre_compressed_accounts_pos)?;

// use anchor_lang::InstructionData;

// let instructiondata = light_system_program::instruction::InvokeCpi {
// inputs: inputs.to_owned(),
// };

// let (sol_pool_pda, is_writable) = if let Some(pool_pda) = ctx.accounts.sol_pool_pda.as_ref() {
// (pool_pda.to_account_info(), true)
// } else {
// (ctx.accounts.light_system_program.to_account_info(), false)
// };

// // Build account infos including both output merkle tree and remaining accounts (compressed mint merkle tree)
// let mut account_infos = vec![
// ctx.accounts.fee_payer.to_account_info(),
// ctx.accounts.cpi_authority_pda.to_account_info(),
// ctx.accounts.registered_program_pda.to_account_info(),
// ctx.accounts.noop_program.to_account_info(),
// ctx.accounts.account_compression_authority.to_account_info(),
// ctx.accounts.account_compression_program.to_account_info(),
// ctx.accounts.self_program.to_account_info(),
// sol_pool_pda,
// ctx.accounts.light_system_program.to_account_info(),
// ctx.accounts.system_program.to_account_info(),
// ctx.accounts.light_system_program.to_account_info(), // cpi_context_account placeholder
// ctx.accounts.merkle_tree.to_account_info(), // output merkle tree
// ];

// // Add remaining accounts (compressed mint merkle tree, etc.)
// account_infos.extend_from_slice(ctx.remaining_accounts);

// // Build account metas
// let mut accounts = vec![
// AccountMeta::new(account_infos[0].key(), true), // fee_payer
// AccountMeta::new_readonly(account_infos[1].key(), true), // cpi_authority_pda (signer)
// AccountMeta::new_readonly(account_infos[2].key(), false), // registered_program_pda
// AccountMeta::new_readonly(account_infos[3].key(), false), // noop_program
// AccountMeta::new_readonly(account_infos[4].key(), false), // account_compression_authority
// AccountMeta::new_readonly(account_infos[5].key(), false), // account_compression_program
// AccountMeta::new_readonly(account_infos[6].key(), false), // self_program
// AccountMeta::new(account_infos[7].key(), is_writable), // sol_pool_pda
// AccountMeta::new_readonly(account_infos[8].key(), false), // decompression_recipient placeholder
// AccountMeta::new_readonly(account_infos[9].key(), false), // system_program
// AccountMeta::new_readonly(account_infos[10].key(), false), // cpi_context_account placeholder
// AccountMeta::new(account_infos[11].key(), false), // output merkle tree (writable)
// ];

// // Add remaining account metas (compressed mint merkle tree should be writable)
// for remaining in &account_infos[12..] {
// accounts.push(AccountMeta::new(remaining.key(), false));
// }

// let instruction = anchor_lang::solana_program::instruction::Instruction {
// program_id: light_system_program::ID,
// accounts,
// data: instructiondata.data(),
// };

// bench_sbf_end!("tm_cpi_mint_update");
// bench_sbf_start!("tm_invoke_mint_update");
// anchor_lang::solana_program::program::invoke_signed(
// &instruction,
// account_infos.as_slice(),
// &[&signer_seeds[..]],
// )?;
// bench_sbf_end!("tm_invoke_mint_update");
// Ok(())
// }
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove commented-out code.

Large blocks of commented-out code should be removed. If this code is needed for reference, consider moving it to documentation or a separate branch.

🤖 Prompt for AI Agents
In programs/compressed-token/src/process_mint.rs between lines 530 and 680,
there is a large block of commented-out code that should be removed to keep the
codebase clean. Delete all the commented-out functions and related code in this
range. If the code needs to be preserved for reference, move it to documentation
or a separate branch instead of leaving it commented out in the source file.

}

#[cfg(test)]
mod tests {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

move to separate test file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant