refactor: sdk, rename CompressedMint -> Mint#2172
Conversation
📝 WalkthroughWalkthroughMass renaming of "CMint"/"CompressedMint" to "Mint" across token-interface, token-sdk, token-client, programs, SDKs, and tests; error variants, instruction payloads/builders, zero-copy state, CPI/account-meta builders, and transfer routing utilities updated to the new Mint-centric names and shapes. Changes
Sequence Diagram(s)mermaid Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
52096b0 to
b8fbff0
Compare
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (10)
sdk-libs/token-client/src/actions/mint_action.rs (1)
164-164: Remove debugprintln!before merging.This debug statement shouldn't ship in SDK code. Consider either removing it entirely or, if the logging is valuable for debugging, converting it to a proper tracing/logging call at an appropriate level (e.g.,
tracing::debug!).Proposed fix
- println!("params {:?}", params);Or if debug logging is desired:
- println!("params {:?}", params); + tracing::debug!(?params, "mint_action_comprehensive params");sdk-libs/token-sdk/src/token/transfer_interface.rs (1)
265-292: Consider simplifyingwith_spl_interfacesignature.All four parameters are
Option<T>, but the function returns an error if any isNone. This creates an odd contract where the caller must provideSomefor all four anyway.If the intent is to require all fields when using SPL interface, consider taking concrete types instead:
♻️ Proposed signature simplification
pub fn with_spl_interface( mut self, - mint: Option<AccountInfo<'info>>, - spl_token_program: Option<AccountInfo<'info>>, - spl_interface_pda: Option<AccountInfo<'info>>, - spl_interface_pda_bump: Option<u8>, - ) -> Result<Self, ProgramError> { - let mint = - mint.ok_or_else(|| ProgramError::Custom(TokenSdkError::MissingMintAccount.into()))?; - - let spl_token_program = spl_token_program - .ok_or_else(|| ProgramError::Custom(TokenSdkError::MissingSplTokenProgram.into()))?; - - let spl_interface_pda = spl_interface_pda - .ok_or_else(|| ProgramError::Custom(TokenSdkError::MissingSplInterfacePda.into()))?; - - let spl_interface_pda_bump = spl_interface_pda_bump.ok_or_else(|| { - ProgramError::Custom(TokenSdkError::MissingSplInterfacePdaBump.into()) - })?; - + mint: AccountInfo<'info>, + spl_token_program: AccountInfo<'info>, + spl_interface_pda: AccountInfo<'info>, + spl_interface_pda_bump: u8, + ) -> Self { self.spl_interface = Some(SplInterfaceCpi { mint, spl_token_program, spl_interface_pda, spl_interface_pda_bump, }); - Ok(self) + self }If there's a specific reason for the
Optionparameters (e.g., framework compatibility where accounts may come as Options), please disregard.sdk-libs/photon-api/src/models/_get_compressed_mint_token_holders_post_request.rs (1)
13-42: Filename inconsistency in auto-generated OpenAPI model code.The struct
GetMintTokenHoldersPostRequesthas been renamed, but the file remains named_get_compressed_mint_token_holders_post_request.rs, which creates a mismatch. The module declaration inmod.rsstill references_get_compressed_mint_token_holders_post_request, keeping the "compressed" qualifier.For consistency with the codebase pattern (where filenames reflect struct names in snake_case), consider updating the OpenAPI spec or generator configuration to produce
_get_mint_token_holders_post_request.rsand update the corresponding module declarations. This applies if the API spec itself has been updated to remove "compressed" from the operation name.sdk-libs/photon-api/src/apis/default_api.rs (1)
753-791: Function name should be renamed to match the types and endpoint it uses.The function is named
get_compressed_mint_token_holders_post, but the types and endpoint omit "compressed":
- Types:
GetMintTokenHoldersPostRequest,GetMintTokenHoldersPost200Response,GetMintTokenHoldersPostError- Endpoint:
/getMintTokenHoldersOther similar functions in this file follow a consistent pattern where the function name matches the type naming—for example,
get_compressed_account_posthas types likeGetCompressedAccountPostRequest. Rename the function toget_mint_token_holders_postto align with the generated types and endpoint. This requires updating one call site insdk-libs/client/src/indexer/photon_indexer.rs.programs/compressed-token/program/src/compressed_token/mint_action/accounts.rs (1)
429-433: Action variant renamed but tracking field still usescmintnaming.The
ZAction::CompressAndCloseMintvariant was correctly updated, but the field storing this detection result is still namedhas_compress_and_close_cmint_action(line 360). For full consistency with the rename, consider also renaming the field tohas_compress_and_close_mint_action.This also applies to other
cmint-prefixed fields inAccountsConfig:
cmint_decompressed(line 350) →mint_decompressed- Methods like
cmint_output_decompressed()(line 368) →mint_output_decompressed()needs_cmint_account()(line 383) →needs_mint_account()If this is intentional to limit scope, that's fine—just noting for future cleanup.
programs/compressed-token/program/src/compressed_token/mint_action/actions/process_actions.rs (1)
146-151: Address naming inconsistency between variant and implementation.The variant was renamed to
ZAction::CompressAndCloseMintbut the function, module, and field names still use the oldcmintsuffix pattern. Update these for consistency:
- Module:
compress_and_close_cmint→compress_and_close_mint- Function:
process_compress_and_close_cmint_action→process_compress_and_close_mint_action- Field:
has_compress_and_close_cmint_action→has_compress_and_close_mint_actionNote: the term "CMint" (compressed mint account) will still appear in comments and documentation, which is correct—this refactoring affects only the action handler naming.
sdk-libs/token-sdk/src/compressed_token/v2/update_compressed_mint/account_metas.rs (2)
8-35: Enforce required authority in the config.
The comment says authority is always required; leaving it optional lets callers build invalid metas. Consider making it non-optional (or fail fast when missing).♻️ Proposed fix (make authority mandatory)
pub struct UpdateMintMetaConfig { pub fee_payer: Option<Pubkey>, - pub authority: Option<Pubkey>, + pub authority: Pubkey, pub in_merkle_tree: Pubkey, pub in_output_queue: Pubkey, pub out_output_queue: Pubkey, pub with_cpi_context: bool, } @@ - if let Some(authority) = config.authority { - metas.push(AccountMeta::new_readonly(authority, true)); - } + metas.push(AccountMeta::new_readonly(config.authority, true));
37-86:with_cpi_contextreturns incomplete metas.
When true, the function skips required accounts (queues/tree/PDAs), yielding an invalid instruction. Either populate CPI-context accounts or explicitly guard/reject this mode until supported.programs/compressed-token/program/src/compressed_token/mint_action/actions/compress_and_close_cmint.rs (1)
16-32: Documentation still uses "CMint" terminology while code uses "Mint".The docstring references "CMint" throughout (lines 16, 20, 21, 22, 24, 27, 31, 32), but the code now uses
Minttype andmint_decompressedfield. Consider updating the documentation for consistency:
- Line 16: "CMint Solana account" → "Mint Solana account"
- Line 20: "CMint doesn't exist" → "Mint doesn't exist"
- Lines 22-27: Update step descriptions to use "Mint" terminology
- Line 31: "compress and close a CMint" → "compress and close a Mint"
Alternatively, if "CMint" is intentionally kept for the concept of a "compressible mint account on-chain", document this distinction clearly.
program-libs/token-interface/tests/compressed_mint.rs (1)
49-107: Consider renaming the helper to reflect Mint terminology.The helper now returns
Mint, so a renamed function would avoid confusion in future test edits.♻️ Suggested rename
-/// Generate a random Mint for testing -fn generate_random_compressed_mint(rng: &mut impl Rng, with_extensions: bool) -> Mint { +/// Generate a random Mint for testing +fn generate_random_mint(rng: &mut impl Rng, with_extensions: bool) -> Mint { @@ - let original_mint = generate_random_compressed_mint(&mut rng, false); + let original_mint = generate_random_mint(&mut rng, false);
🤖 Fix all issues with AI agents
In `@program-libs/token-interface/src/state/mint/top_up.rs`:
- Around line 11-17: Introduce Mint-prefixed constants and keep the existing
CMINT_* names as deprecated aliases: create new public constants named
MINT_MIN_SIZE_WITH_COMPRESSION and MINT_COMPRESSION_INFO_OFFSET (and any other
CMINT_* constants referenced around the other occurrences) initialized to the
same values currently used, then change the existing CMINT_* declarations to be
deprecated aliases that simply equal the new MINT_* constants (use
#[deprecated(note = "...")] on the CMINT_* declarations). Reference the symbols
CMINT_MIN_SIZE_WITH_COMPRESSION and COMPRESSION_INFO_OFFSET (and the other
CMINT_* symbols mentioned) when adding the new MINT_* constants and making the
old CMINT_* consts forward to them.
In `@program-libs/token-interface/tests/hash_tests.rs`:
- Around line 1-10: Uncomment the entire test module hash_tests and restore the
unit tests exercising Mint::hash(), ensuring signatures and imports match
current types (use light_token_interface::state::{Mint, MintMetadata, BaseMint}
and light_compressed_account::Pubkey); run the tests and fix any compile errors
by updating uses of Option vs zero semantics, authority handling, or renamed
methods/fields referenced in tests (e.g., Mint::hash, Mint::new,
MintMetadata::default), and ensure the randomized 1k stress test compiles and
asserts deterministic, non-zero, and collision-free outputs for varied authority
combinations and boundary values.
In
`@programs/compressed-token/program/src/compressed_token/mint_action/actions/create_mint.rs`:
- Around line 111-115: The error message referencing the old "CMint" name is
inconsistent with the renamed field mint.metadata.mint_decompressed; update the
message in create_mint.rs (where you validate mint.metadata.mint_decompressed !=
0) to use a consistent phrase such as "New mint must not be decompressed" or
"New mint must start without decompressed mint" so the log matches the renamed
field and intent.
In `@sdk-libs/token-client/src/instructions/create_mint.rs`:
- Around line 38-64: You derive the compressed mint address with
rpc.get_address_tree_v2() and then call create_mint_action_instruction which
itself fetches the address tree, risking a mismatch if the tree rotates; pass
the same tree (address_tree_pubkey) into the instruction builder (e.g., add a
tree parameter to create_mint_action_instruction or MintActionParams) or move
the derive_mint_compressed_address call into the mint_action.rs path so there is
a single source of truth (referencing get_address_tree_v2,
derive_mint_compressed_address, create_mint_action_instruction,
MintActionParams). Also verify the on-chain MintAction accepts an empty actions
Vec for a create-only flow; if it does not, populate MintActionParams.actions
with the explicit create action instead of vec![] to ensure the create-only
behavior is encoded.
In
`@sdk-libs/token-sdk/src/compressed_token/v2/mint_to_compressed/instruction.rs`:
- Around line 18-19: Rename the field compressed_mint_inputs on struct
MintToCompressedInputs to reflect the renamed type MintWithContext (suggest
mint_inputs or mint_with_context) to keep the API consistent; update all places
that pattern-match/destructure MintToCompressedInputs and any usages that
reference compressed_mint_inputs to the new field name, and keep or add a short
comment if you intentionally retain the old name for backwards compatibility.
In `@sdk-libs/token-sdk/src/token/create_mint.rs`:
- Around line 34-39: Add a client-side validation that returns an error if
rent_payment < 2 before constructing the on-chain instruction: inside the
builder/function that creates the mint instruction (e.g., the method that
assembles the CreateMint/CreateMintInstruction or build() function in
create_mint.rs), check the struct field rent_payment and early-return a
descriptive error (or Result::Err) when rent_payment is less than 2 so callers
fail fast instead of relying on on-chain rejection.
- Around line 279-301: Add explicit key validations inside
TryFrom<&CreateMintCpi> so callers cannot pass mismatched accounts: check that
params.mint == mint.key, compressible_config.key == config_pda(), and
rent_sponsor.key == rent_sponsor_pda() (these mirror what
CreateMint::instruction() hardcodes), and return an Err on mismatch; keep
existing check of params.mint_authority == authority. This ensures the CPI
account ordering used in invoke()/invoke_signed() (mint_seed, payer,
address_tree, etc.) will fail fast on bad inputs.
In `@sdk-libs/token-sdk/src/token/transfer_interface.rs`:
- Around line 173-188: The From<&TransferInterfaceCpi> for TransferInterface
implementation currently sets max_top_up: None because TransferInterfaceCpi
lacks that field; either document this intentional omission or (if CPI callers
should control rent top-up) add a max_top_up: Option<u16> field to the
TransferInterfaceCpi struct and propagate it in the conversion: update the
TransferInterfaceCpi definition to include max_top_up and modify the impl
From<&TransferInterfaceCpi> for TransferInterface to map max_top_up:
cpi.max_top_up (preserving Option semantics), ensuring any constructors/parsers
of TransferInterfaceCpi are also updated to accept/forward this field.
- Around line 302-316: The code currently calls determine_transfer_type twice
(once in TransferInterface::invoke and again inside
TransferInterface::instruction/TransferInterface::from), so modify the API to
compute the transfer type once and reuse it: in TransferInterface::invoke call
determine_transfer_type(self.source_account.owner,
self.destination_account.owner) and then call a new/internal method like
instruction_with_type(&self, transfer_type: TransferType) (or change instruction
to accept a TransferType parameter) so the instruction builder uses the
pre-computed transfer_type instead of calling determine_transfer_type again;
update TransferInterface::instruction() usages accordingly (or keep it for
backward compatibility) and ensure TransferInterface::invoke uses the new
instruction_with_type when building the CPI instruction before calling
solana_cpi::invoke.
In `@sdk-libs/token-sdk/src/utils.rs`:
- Around line 32-35: The code compares owner against a hard-coded SPL Token
program pubkey created via Pubkey::from_str_const; replace that hard-coded value
with the canonical constant spl_token::ID (and remove the temporary spl_token
variable) so the if-check becomes a comparison against spl_token::ID and
spl_token_2022::ID (i.e., use spl_token::ID and token_22/spl_token_2022::ID in
the owner equality checks).
programs/compressed-token/program/src/compressed_token/mint_action/actions/create_mint.rs
Outdated
Show resolved
Hide resolved
| // Get address tree for deriving compressed mint address | ||
| let address_tree_pubkey = rpc.get_address_tree_v2().tree; | ||
|
|
||
| let output_queue = rpc.get_random_state_tree_info()?.queue; | ||
|
|
||
| let compressed_mint_address = | ||
| derive_mint_compressed_address(&mint_seed.pubkey(), &address_tree_pubkey); | ||
|
|
||
| // Create extensions if metadata is provided | ||
| let extensions = metadata.map(|meta| vec![ExtensionInstructionData::TokenMetadata(meta)]); | ||
|
|
||
| // Get validity proof for address creation | ||
| let rpc_result = rpc | ||
| .get_validity_proof( | ||
| vec![], | ||
| vec![light_client::indexer::AddressWithTree { | ||
| address: compressed_mint_address, | ||
| tree: address_tree_pubkey, | ||
| }], | ||
| None, | ||
| ) | ||
| .await? | ||
| .value; | ||
|
|
||
| let address_merkle_tree_root_index = rpc_result.addresses[0].root_index; | ||
| let (mint, bump) = find_mint_address(&mint_seed.pubkey()); | ||
| // Build params struct manually | ||
| let params = CreateMintParams { | ||
| decimals, | ||
| address_merkle_tree_root_index, | ||
| mint_authority, | ||
| proof: rpc_result.proof.0.unwrap(), | ||
| compression_address: compressed_mint_address, | ||
| mint, | ||
| bump, | ||
| freeze_authority, | ||
| extensions, | ||
| }; | ||
|
|
||
| // Create instruction builder | ||
| let builder = CreateMint::new( | ||
| params, | ||
| mint_seed.pubkey(), | ||
| payer, | ||
| address_tree_pubkey, | ||
| output_queue, | ||
| let compressed_mint_address = light_token_sdk::token::derive_mint_compressed_address( | ||
| &mint_seed.pubkey(), | ||
| &address_tree_pubkey, | ||
| ); | ||
|
|
||
| builder | ||
| .instruction() | ||
| .map_err(|e| RpcError::CustomError(format!("Token SDK error: {:?}", e))) | ||
| // Create compressed-only mint using MintAction with empty actions | ||
| create_mint_action_instruction( | ||
| rpc, | ||
| MintActionParams { | ||
| compressed_mint_address, | ||
| mint_seed: mint_seed.pubkey(), | ||
| authority: mint_authority, | ||
| payer, | ||
| actions: vec![], // No actions - just create compressed mint | ||
| new_mint: Some(NewMint { | ||
| decimals, | ||
| supply: 0, | ||
| mint_authority, | ||
| freeze_authority, | ||
| metadata, | ||
| version: 3, | ||
| }), | ||
| }, | ||
| ) | ||
| .await |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Verify create-only MintAction behavior and address-tree consistency.
You derive the compressed address via rpc.get_address_tree_v2, but create_mint_action_instruction fetches the address tree internally (sdk-libs/token-client/src/instructions/mint_action.rs, Lines 108-385). If the tree can rotate between calls, the derived address could drift from the config used in the instruction. Consider plumbing the tree into the instruction builder (or deriving there) to keep a single source of truth. Also confirm that an empty actions vec is accepted for “create-only” in the on-chain MintAction flow; if not, include the explicit create action.
🤖 Prompt for AI Agents
In `@sdk-libs/token-client/src/instructions/create_mint.rs` around lines 38 - 64,
You derive the compressed mint address with rpc.get_address_tree_v2() and then
call create_mint_action_instruction which itself fetches the address tree,
risking a mismatch if the tree rotates; pass the same tree (address_tree_pubkey)
into the instruction builder (e.g., add a tree parameter to
create_mint_action_instruction or MintActionParams) or move the
derive_mint_compressed_address call into the mint_action.rs path so there is a
single source of truth (referencing get_address_tree_v2,
derive_mint_compressed_address, create_mint_action_instruction,
MintActionParams). Also verify the on-chain MintAction accepts an empty actions
Vec for a create-only flow; if it does not, populate MintActionParams.actions
with the explicit create action instead of vec![] to ensure the create-only
behavior is encoded.
| pub struct MintToCompressedInputs { | ||
| pub compressed_mint_inputs: CompressedMintWithContext, | ||
| pub compressed_mint_inputs: MintWithContext, |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider renaming the field to match the type rename.
The type was renamed from CompressedMintWithContext → MintWithContext, but the field is still called compressed_mint_inputs. This creates an inconsistency where the field name implies "compressed" but the type no longer carries that prefix.
For API consistency, consider renaming to mint_inputs or mint_with_context. If you're intentionally preserving the field name to minimize breaking changes for consumers, that's a reasonable tradeoff—just worth documenting.
♻️ Optional rename for consistency
pub struct MintToCompressedInputs {
- pub compressed_mint_inputs: MintWithContext,
+ pub mint_inputs: MintWithContext,And update the destructuring at line 42:
let MintToCompressedInputs {
- compressed_mint_inputs,
+ mint_inputs,And the usage at line 64:
- compressed_mint_inputs.clone(),
+ mint_inputs.clone(),🤖 Prompt for AI Agents
In `@sdk-libs/token-sdk/src/compressed_token/v2/mint_to_compressed/instruction.rs`
around lines 18 - 19, Rename the field compressed_mint_inputs on struct
MintToCompressedInputs to reflect the renamed type MintWithContext (suggest
mint_inputs or mint_with_context) to keep the API consistent; update all places
that pattern-match/destructure MintToCompressedInputs and any usages that
reference compressed_mint_inputs to the new field name, and keep or add a short
comment if you intentionally retain the old name for backwards compatibility.
| // Account order must match MintActionMetaConfig::to_account_metas() | ||
| let mut account_infos = vec![ | ||
| self.system_accounts.light_system_program, // Index 0 | ||
| self.mint_seed, // Index 1 | ||
| self.authority, // Index 2 (authority) | ||
| self.payer, // Index 3 (fee_payer) | ||
| self.system_accounts.light_system_program, | ||
| self.mint_seed, | ||
| self.authority, | ||
| self.compressible_config, | ||
| self.mint, | ||
| self.rent_sponsor, | ||
| 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.address_tree, | ||
| ]; | ||
|
|
||
| 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.address_tree); | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find the create_mint.rs file and explore the sdk-libs structure
find . -type f -name "create_mint.rs" | head -20Repository: Lightprotocol/light-protocol
Length of output: 368
🏁 Script executed:
#!/bin/bash
# List the structure of sdk-libs/token-sdk/src/token/
ls -la sdk-libs/token-sdk/src/token/ 2>/dev/null || echo "Directory not found, checking sdk-libs structure..."
find sdk-libs -type d -name token-sdk 2>/dev/null | head -5Repository: Lightprotocol/light-protocol
Length of output: 1700
🏁 Script executed:
#!/bin/bash
# Search for MintActionMetaConfig to understand account ordering
rg -n "MintActionMetaConfig" --type=rs | head -30Repository: Lightprotocol/light-protocol
Length of output: 98
🏁 Script executed:
#!/bin/bash
# Search for MintActionMetaConfig with correct syntax
rg -n "MintActionMetaConfig" --type rust | head -40Repository: Lightprotocol/light-protocol
Length of output: 5197
🏁 Script executed:
#!/bin/bash
# Read the create_mint.rs file to see the full context
wc -l sdk-libs/token-sdk/src/token/create_mint.rsRepository: Lightprotocol/light-protocol
Length of output: 119
🏁 Script executed:
#!/bin/bash
# Read lines around 279-330 to see the CPI account ordering
sed -n '270,335p' sdk-libs/token-sdk/src/token/create_mint.rsRepository: Lightprotocol/light-protocol
Length of output: 2363
🏁 Script executed:
#!/bin/bash
# Read the MintActionMetaConfig implementation to see to_account_metas()
cat -n sdk-libs/token-sdk/src/compressed_token/v2/mint_action/account_metas.rs | head -150Repository: Lightprotocol/light-protocol
Length of output: 6074
🏁 Script executed:
#!/bin/bash
# Continue reading to find the to_account_metas() method
sed -n '100,250p' sdk-libs/token-sdk/src/compressed_token/v2/mint_action/account_metas.rsRepository: Lightprotocol/light-protocol
Length of output: 4943
🏁 Script executed:
#!/bin/bash
# Search for TryFrom implementation for CreateMintCpi
sed -n '330,393p' sdk-libs/token-sdk/src/token/create_mint.rsRepository: Lightprotocol/light-protocol
Length of output: 2460
🏁 Script executed:
#!/bin/bash
# Read the CreateMintCpi struct definition to understand the accounts
sed -n '1,150p' sdk-libs/token-sdk/src/token/create_mint.rsRepository: Lightprotocol/light-protocol
Length of output: 5295
🏁 Script executed:
#!/bin/bash
# Search for where CreateMintCpi is used or constructed to understand how mint_seed relates to mint_signer
rg -n "mint_seed|CreateMintCpi" sdk-libs/token-sdk/src/token/create_mint.rs | head -30Repository: Lightprotocol/light-protocol
Length of output: 1560
🏁 Script executed:
#!/bin/bash
# Check the CreateMintCpi struct definition fully to understand all accounts
sed -n '222,275p' sdk-libs/token-sdk/src/token/create_mint.rsRepository: Lightprotocol/light-protocol
Length of output: 1890
🏁 Script executed:
#!/bin/bash
# Check for dependencies in sdk-libs/token-sdk/Cargo.toml
head -50 sdk-libs/token-sdk/Cargo.tomlRepository: Lightprotocol/light-protocol
Length of output: 1753
🏁 Script executed:
#!/bin/bash
# Let's verify the account order by examining how to_account_metas builds the list for a create_mint scenario
# and compare it explicitly with the invoke() method
sed -n '142,230p' sdk-libs/token-sdk/src/compressed_token/v2/mint_action/account_metas.rs | cat -nRepository: Lightprotocol/light-protocol
Length of output: 3732
🏁 Script executed:
#!/bin/bash
# Search for examples of CreateMintCpi usage to see if there are potential mismatches
rg -n "CreateMintCpi\|CreateMintCpi::new" sdk-libs/ sdk-tests/ -A 5 | head -60Repository: Lightprotocol/light-protocol
Length of output: 54
🏁 Script executed:
#!/bin/bash
# Check what config_pda() and rent_sponsor_pda() functions do
rg -n "fn config_pda|fn rent_sponsor_pda" sdk-libs/token-sdk/src/ -A 5Repository: Lightprotocol/light-protocol
Length of output: 787
🏁 Script executed:
#!/bin/bash
# Look at actual test usage of CreateMintCpi to see how it's constructed
rg -n "CreateMintCpi::new\|CreateMintCpi {" sdk-tests/ -B 3 -A 10 | head -80Repository: Lightprotocol/light-protocol
Length of output: 205
🏁 Script executed:
#!/bin/bash
# Check if there are any instruction building examples showing the actual account flow
rg -n "new_create_mint\|CreateMint::new" sdk-libs/token-client/ -B 2 -A 8 | head -80Repository: Lightprotocol/light-protocol
Length of output: 54
🏁 Script executed:
#!/bin/bash
# Verify that mint_seed and mint are indeed the same derived address by checking the find_mint_address usage
rg -n "find_mint_address" sdk-libs/token-sdk/src/ -B 1 -A 2Repository: Lightprotocol/light-protocol
Length of output: 4094
🏁 Script executed:
#!/bin/bash
# Create a comparison analysis of the two account orderings
python3 << 'EOF'
# Account order from to_account_metas() for create_mint scenario
to_account_metas_order = [
"light_system_program", # 1
"mint_signer", # 2 (from new_create_mint)
"authority", # 3
"compressible_config", # 4 (optional, set for create_mint)
"mint", # 5 (optional, set for create_mint)
"rent_sponsor", # 6 (optional, set for create_mint)
"fee_payer", # 7
"cpi_authority_pda", # 8
"registered_program_pda", # 9
"account_compression_authority", # 10
"account_compression_program", # 11
"system_program", # 12
"cpi_context", # 13 (optional)
"output_queue", # 14
"tree_pubkey", # 15
]
# Account order from invoke() method (lines 279-301)
invoke_order = [
"light_system_program", # 1
"mint_seed", # 2 <-- POTENTIAL ISSUE: labeled as mint_seed, but should be mint_signer
"authority", # 3
"compressible_config", # 4
"mint", # 5
"rent_sponsor", # 6
"payer", # 7
"cpi_authority_pda", # 8
"registered_program_pda", # 9
"account_compression_authority", # 10
"account_compression_program", # 11
"system_program", # 12
"cpi_context_account", # 13 (optional)
"output_queue", # 14
"address_tree", # 15
]
print("Position Comparison:")
for i, (to_meta, invoke) in enumerate(zip(to_account_metas_order, invoke_order), 1):
marker = " <-- MATCH" if to_meta.split('_')[0] == invoke.split('_')[0] or \
(to_meta == "tree_pubkey" and invoke == "address_tree") or \
(to_meta == "fee_payer" and invoke == "payer") or \
(to_meta == "mint_signer" and invoke == "mint_seed") else " <-- SEMANTIC MATCH (renamed)"
print(f"{i:2}. to_account_metas: {to_meta:40} | invoke: {invoke:40}{marker}")
print("\n✓ Account order MATCHES semantically")
print("✓ mint_seed is the account used as mint_signer")
print("✓ payer is the fee_payer")
print("✓ address_tree is the tree_pubkey")
EOFRepository: Lightprotocol/light-protocol
Length of output: 158
🏁 Script executed:
#!/bin/bash
# Now let's check if there are any validations already in place for the CPI accounts
sed -n '335,365p' sdk-libs/token-sdk/src/token/create_mint.rsRepository: Lightprotocol/light-protocol
Length of output: 1344
🏁 Script executed:
#!/bin/bash
# Verify account order by examining CreateMint::instruction() which builds the metadata
sed -n '145,180p' sdk-libs/token-sdk/src/token/create_mint.rsRepository: Lightprotocol/light-protocol
Length of output: 1425
🏁 Script executed:
#!/bin/bash
# Check if params.mint is validated anywhere in CreateMint
rg -n "params\.mint" sdk-libs/token-sdk/src/token/create_mint.rsRepository: Lightprotocol/light-protocol
Length of output: 595
🏁 Script executed:
#!/bin/bash
# See how mint_seed_pubkey relates to params.mint in the instruction building
sed -n '125,170p' sdk-libs/token-sdk/src/token/create_mint.rsRepository: Lightprotocol/light-protocol
Length of output: 1976
Account ordering is correct; add missing key validations to TryFrom.
The CPI account order in invoke() and invoke_signed() correctly matches MintActionMetaConfig::to_account_metas() (mint_seed acts as mint_signer, payer as fee_payer, address_tree as tree_pubkey). However, TryFrom<&CreateMintCpi> only validates params.mint_authority against the authority account. Since CreateMint::instruction() hardcodes config_pda(), rent_sponsor_pda(), and uses params.mint from parameters, add guards to ensure callers pass matching accounts:
- Validate
params.mint == mint.key(caller's mint account must match params) - Validate
compressible_config.key == config_pda() - Validate
rent_sponsor.key == rent_sponsor_pda()
Without these checks, mismatched accounts fail silently during CPI invocation.
Proposed validation addition
fn try_from(account_infos: &CreateMintCpi<'info>) -> Result<Self, Self::Error> {
if account_infos.params.mint_authority != *account_infos.authority.key {
solana_msg::msg!(
"CreateMintCpi: params.mint_authority ({}) does not match authority account ({})",
account_infos.params.mint_authority,
account_infos.authority.key
);
return Err(ProgramError::InvalidAccountData);
}
+ if account_infos.params.mint != *account_infos.mint.key {
+ solana_msg::msg!(
+ "CreateMintCpi: params.mint ({}) does not match mint account ({})",
+ account_infos.params.mint,
+ account_infos.mint.key
+ );
+ return Err(ProgramError::InvalidAccountData);
+ }
+ if *account_infos.compressible_config.key != config_pda() {
+ solana_msg::msg!(
+ "CreateMintCpi: compressible_config ({}) must be config_pda ({})",
+ account_infos.compressible_config.key,
+ &config_pda()
+ );
+ return Err(ProgramError::InvalidAccountData);
+ }
+ if *account_infos.rent_sponsor.key != rent_sponsor_pda() {
+ solana_msg::msg!(
+ "CreateMintCpi: rent_sponsor ({}) must be rent_sponsor_pda ({})",
+ account_infos.rent_sponsor.key,
+ &rent_sponsor_pda()
+ );
+ return Err(ProgramError::InvalidAccountData);
+ }
Ok(Self {
mint_seed_pubkey: *account_infos.mint_seed.key,
payer: *account_infos.payer.key,
address_tree_pubkey: *account_infos.address_tree.key,
output_queue: *account_infos.output_queue.key,
cpi_context: account_infos.cpi_context.clone(),
cpi_context_pubkey: account_infos
.cpi_context_account
.as_ref()
.map(|acc| *acc.key),
params: account_infos.params.clone(),
})
}Also applies to: 308-330
🤖 Prompt for AI Agents
In `@sdk-libs/token-sdk/src/token/create_mint.rs` around lines 279 - 301, Add
explicit key validations inside TryFrom<&CreateMintCpi> so callers cannot pass
mismatched accounts: check that params.mint == mint.key, compressible_config.key
== config_pda(), and rent_sponsor.key == rent_sponsor_pda() (these mirror what
CreateMint::instruction() hardcodes), and return an Err on mismatch; keep
existing check of params.mint_authority == authority. This ensures the CPI
account ordering used in invoke()/invoke_signed() (mint_seed, payer,
address_tree, etc.) will fail fast on bad inputs.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@sdk-libs/token-sdk/src/token/transfer_interface.rs`:
- Around line 24-28: The doc comments for the transfer-type determination are
out of sync: update the function-level and related docstrings that currently
claim SPL→SPL returns UseRegularSplTransfer to instead describe the current
behavior (SPL→SPL returns TransferType::SplToSpl or an
Err(SplTokenProgramMismatch) when token program ids differ, and
Err(CannotDetermineAccountType) for unrecognized owners). Update all instances
mentioning UseRegularSplTransfer (including the other two occurrences) to
reference TransferType::SplToSpl and
SplTokenProgramMismatch/CannotDetermineAccountType as appropriate so the docs
match the implementation in the determine-transfer logic.
- Around line 184-199: Replace the manual byte-level encoding of a
TransferChecked instruction with the official SPL Token instruction builder:
call the appropriate transfer_checked function (e.g.
spl_token::instruction::transfer_checked or the token-2022 equivalent) instead
of constructing data = vec![12u8] + amount bytes + decimals; pass self.amount,
self.decimals, spl.mint, self.source, self.destination, self.authority and the
correct token program id (instead of self.source_owner) to that builder so it
returns an Instruction with the correct program_id and AccountMeta list; also
verify you import and use the token-2022 crate/version when building
instructions for token-2022 compatibility.
♻️ Duplicate comments (2)
sdk-libs/token-sdk/src/token/transfer_interface.rs (2)
205-218: Exposemax_top_upfor CPI callers (still hardcoded toNone).CPI users cannot set a rent/top-up cap. Either document this as intentional or plumb the field through
TransferInterfaceCpi.
337-340: Avoid recomputing transfer type ininvoke/invoke_signed.You compute
transfer_typeand then callinstruction(), which recomputes it again viaTransferInterface::from(self). Consider reusing the computed value.Also applies to: 407-410
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
sdk-tests/sdk-light-token-test/tests/test_transfer_interface.rsis excluded by none and included by none
📒 Files selected for processing (2)
sdk-libs/token-sdk/src/error.rssdk-libs/token-sdk/src/token/transfer_interface.rs
🧰 Additional context used
📓 Path-based instructions (1)
sdk-libs/**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
sdk-libs/**/*.rs: SDK libs must depend only on program-libs, light-prover-client, and external crates
SDK libs must not depend on programs without devenv feature
Files:
sdk-libs/token-sdk/src/error.rssdk-libs/token-sdk/src/token/transfer_interface.rs
🧠 Learnings (43)
📓 Common learnings
Learnt from: CR
Repo: Lightprotocol/program-examples PR: 0
File: airdrop-implementations/simple-claim/README.md:0-0
Timestamp: 2026-01-10T19:24:56.367Z
Learning: Applies to airdrop-implementations/simple-claim/**/*.rs : Tokens must be minted as compressed tokens to PDAs derived from `[claimant, mint, unlock_slot, bump]`
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/compressed-token/program/CLAUDE.md:0-0
Timestamp: 2026-01-14T00:06:46.444Z
Learning: Applies to programs/compressed-token/program/src/compressed_token/mint_action/**/*.rs : MintAction instruction must support exactly 10 action types: CreateCompressedMint, MintTo, UpdateMintAuthority, UpdateFreezeAuthority, MintToCToken, UpdateMetadataField, UpdateMetadataAuthority, RemoveMetadataKey, DecompressMint, and CompressAndCloseCMint
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/compressed-token/program/docs/CLAUDE.md:0-0
Timestamp: 2026-01-12T14:27:56.326Z
Learning: Applies to programs/compressed-token/program/docs/compressed_token/{TRANSFER2,MINT_ACTION,FREEZE,THAW,CREATE_TOKEN_POOL,ADD_TOKEN_POOL}.md : Compressed token operations documentation should be organized in a compressed_token/ subdirectory with separate files for TRANSFER2.md (batch transfer with compress/decompress), MINT_ACTION.md (mint operations), FREEZE.md (freeze operations), THAW.md (thaw operations), CREATE_TOKEN_POOL.md (initial token pool creation), and ADD_TOKEN_POOL.md (additional token pools)
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/account-checks/docs/PACKED_ACCOUNTS.md:0-0
Timestamp: 2025-11-24T17:59:54.233Z
Learning: Applies to program-libs/account-checks/docs/program-libs/account-checks/src/**/*.rs : Provide descriptive names in ProgramPackedAccounts error messages (e.g., 'token_mint' instead of 'account')
Learnt from: CR
Repo: Lightprotocol/program-examples PR: 0
File: create-and-update/README.md:0-0
Timestamp: 2026-01-10T19:25:28.052Z
Learning: Applies to create-and-update/**/*.rs : Use `LightAccount::new_mut()` to update existing compressed accounts
Learnt from: CR
Repo: Lightprotocol/distributor PR: 0
File: programs/merkle-distributor/CLAUDE.md:0-0
Timestamp: 2026-01-11T01:05:19.378Z
Learning: Applies to programs/merkle-distributor/**/instructions/{new_claim,claim_locked}.rs : Use Light SDK v2 CPI via `LightSystemProgramCpi::new_cpi` for compressed account interactions
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/compressed-token/program/CLAUDE.md:0-0
Timestamp: 2026-01-14T00:06:46.444Z
Learning: Applies to programs/compressed-token/program/src/compressed_token/transfer2/**/*.rs : Transfer2 instruction must perform sum checks when supporting multi-mint Compress, Decompress, and CompressAndClose operations
Learnt from: CR
Repo: Lightprotocol/program-examples PR: 0
File: account-comparison/CLAUDE.md:0-0
Timestamp: 2026-01-10T19:26:01.412Z
Learning: Applies to account-comparison/programs/**/src/**/*.rs : Use `LightAccount::new_init` for compressed account creation and `LightAccount::new_mut` for updates in Light Protocol implementations
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T17:55:17.323Z
Learning: Applies to sdk-libs/macros/src/compressible/**/decompress_context.rs : Decompression trait implementation (`DecompressContext`) with account accessors, PDA/token separation logic, and token processing delegation should be in `decompress_context.rs`
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-tests/sdk-light-token-test/README.md:0-0
Timestamp: 2026-01-14T00:05:32.217Z
Learning: Implement all 8 compressed token instructions: create_cmint, mint_to_ctoken, create_token_account_invoke, create_token_account_invoke_signed, create_ata_invoke, create_ata_invoke_signed, transfer_interface_invoke, and transfer_interface_invoke_signed
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/compressed-token/program/docs/CLAUDE.md:0-0
Timestamp: 2026-01-12T14:27:56.326Z
Learning: Applies to programs/compressed-token/program/docs/ctoken/{CREATE,CLOSE,TRANSFER,TRANSFER_CHECKED,APPROVE,REVOKE,MINT_TO,MINT_TO_CHECKED,BURN,BURN_CHECKED,FREEZE_ACCOUNT,THAW_ACCOUNT}.md : CToken account operations documentation should be organized in a ctoken/ subdirectory with files for account creation, closure, transfers, approval delegation, minting, burning, and freeze/thaw operations
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-tests/sdk-light-token-test/README.md:0-0
Timestamp: 2026-01-14T00:05:32.217Z
Learning: Applies to sdk-tests/sdk-light-token-test/**/*.rs : Use the builder pattern from `light-token-sdk::ctoken` module for CPI operations instead of manual instruction building
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/account-checks/docs/ACCOUNT_ITERATOR.md:0-0
Timestamp: 2025-11-24T17:59:13.714Z
Learning: Applies to program-libs/account-checks/docs/**/*.rs : Use descriptive account names when calling AccountIterator methods (e.g., `iter.next_account("token_mint")` instead of `iter.next_account("account_3")`)
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-tests/CLAUDE.md:0-0
Timestamp: 2026-01-14T00:06:28.451Z
Learning: Compressed token tests should include core token tests (light_token, v1, mint, transfer2) and batched tree tests
📚 Learning: 2026-01-14T00:06:46.444Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/compressed-token/program/CLAUDE.md:0-0
Timestamp: 2026-01-14T00:06:46.444Z
Learning: Applies to programs/compressed-token/program/**/*.rs : When handling errors from functions returning TokenError directly (e.g., unpack_amount_and_decimals), use `convert_token_error` to map SPL Token error codes (0-18) to named ErrorCode variants
Applied to files:
sdk-libs/token-sdk/src/error.rssdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-14T00:06:46.444Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/compressed-token/program/CLAUDE.md:0-0
Timestamp: 2026-01-14T00:06:46.444Z
Learning: Applies to programs/compressed-token/program/**/*.rs : When converting SPL Token operation errors from pinocchio token program processors, use `convert_pinocchio_token_error` to map error codes (0-18) to named ErrorCode variants
Applied to files:
sdk-libs/token-sdk/src/error.rssdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-14T00:06:46.444Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/compressed-token/program/CLAUDE.md:0-0
Timestamp: 2026-01-14T00:06:46.444Z
Learning: Applies to programs/compressed-token/program/**/*.rs : When converting errors from system program operations, data access operations, or lamport transfers, use `convert_program_error` which adds a +6000 offset to raw error codes
Applied to files:
sdk-libs/token-sdk/src/error.rs
📚 Learning: 2025-11-24T17:59:46.693Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/account-checks/docs/ERRORS.md:0-0
Timestamp: 2025-11-24T17:59:46.693Z
Learning: Applies to program-libs/account-checks/docs/program-libs/account-checks/src/error.rs : All AccountError variants must convert automatically to `ProgramError::Custom(u32)` for both solana-program and pinocchio SDKs using From trait implementations
Applied to files:
sdk-libs/token-sdk/src/error.rssdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-14T00:06:11.915Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/CLAUDE.md:0-0
Timestamp: 2026-01-14T00:06:11.915Z
Learning: Applies to program-libs/compressible/src/error.rs : Error types in error.rs must use numeric codes in the 19xxx range for CToken-specific errors
Applied to files:
sdk-libs/token-sdk/src/error.rs
📚 Learning: 2026-01-11T01:05:19.378Z
Learnt from: CR
Repo: Lightprotocol/distributor PR: 0
File: programs/merkle-distributor/CLAUDE.md:0-0
Timestamp: 2026-01-11T01:05:19.378Z
Learning: Applies to programs/merkle-distributor/**/error.rs : Define error codes as an `ErrorCode` enum in error.rs with proper variants
Applied to files:
sdk-libs/token-sdk/src/error.rs
📚 Learning: 2026-01-14T00:06:00.109Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/account-checks/CLAUDE.md:0-0
Timestamp: 2026-01-14T00:06:00.109Z
Learning: Applies to program-libs/account-checks/**/*.rs : Define error codes in the range 12006-12021 with automatic ProgramError conversion for both solana-program and pinocchio SDKs
Applied to files:
sdk-libs/token-sdk/src/error.rs
📚 Learning: 2026-01-14T00:06:11.915Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/CLAUDE.md:0-0
Timestamp: 2026-01-14T00:06:11.915Z
Learning: Applies to program-libs/compressible/src/error.rs : Implement error type conversions (ProgramError) for Anchor, Pinocchio, and Solana program compatibility
Applied to files:
sdk-libs/token-sdk/src/error.rssdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2025-11-24T17:56:00.229Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:56:00.229Z
Learning: Applies to program-libs/batched-merkle-tree/docs/**/*.rs : Error handling must use BatchedMerkleTreeError enum from errors.rs with u32 error codes in the 14301-14312 range
Applied to files:
sdk-libs/token-sdk/src/error.rs
📚 Learning: 2026-01-10T19:26:10.578Z
Learnt from: CR
Repo: Lightprotocol/program-examples PR: 0
File: airdrop-implementations/simple-claim/CLAUDE.md:0-0
Timestamp: 2026-01-10T19:26:10.578Z
Learning: Applies to airdrop-implementations/simple-claim/program/src/error.rs : Define ClaimError enum with three variants: MissingRequiredSignature, TokensLocked, and InvalidPDA
Applied to files:
sdk-libs/token-sdk/src/error.rssdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-10T19:26:10.578Z
Learnt from: CR
Repo: Lightprotocol/program-examples PR: 0
File: airdrop-implementations/simple-claim/CLAUDE.md:0-0
Timestamp: 2026-01-10T19:26:10.578Z
Learning: Applies to airdrop-implementations/simple-claim/program/src/processor.rs : Invoke light_ctoken_sdk::decompress via CPI to convert compressed tokens to SPL tokens in the Claim instruction processor
Applied to files:
sdk-libs/token-sdk/src/error.rssdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2025-11-24T17:59:46.693Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/account-checks/docs/ERRORS.md:0-0
Timestamp: 2025-11-24T17:59:46.693Z
Learning: Applies to program-libs/account-checks/docs/program-libs/account-checks/src/error.rs : Map Pinocchio standard ProgramError variants (InvalidArgument, InvalidInstructionData, InvalidAccountData, AccountDataTooSmall, InsufficientFunds, IncorrectProgramId, MissingRequiredSignature, AccountAlreadyInitialized, UninitializedAccount, NotEnoughAccountKeys, AccountBorrowFailed) to AccountError::PinocchioProgramError with codes 1-11
Applied to files:
sdk-libs/token-sdk/src/error.rs
📚 Learning: 2026-01-14T00:06:46.444Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/compressed-token/program/CLAUDE.md:0-0
Timestamp: 2026-01-14T00:06:46.444Z
Learning: Applies to programs/compressed-token/program/src/ctoken/*.rs : CToken operations must validate that the CompressibleConfig state is ACTIVE only for CreateTokenAccount, CreateAssociatedTokenAccount, and CreateAssociatedTokenAccountIdempotent instructions
Applied to files:
sdk-libs/token-sdk/src/error.rs
📚 Learning: 2026-01-14T00:06:11.915Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/CLAUDE.md:0-0
Timestamp: 2026-01-14T00:06:11.915Z
Learning: Applies to program-libs/compressible/src/error.rs : Propagate HasherError from light-hasher library (7xxx error codes) in error handling
Applied to files:
sdk-libs/token-sdk/src/error.rs
📚 Learning: 2025-11-24T17:59:46.693Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/account-checks/docs/ERRORS.md:0-0
Timestamp: 2025-11-24T17:59:46.693Z
Learning: Applies to program-libs/account-checks/docs/program-libs/account-checks/src/error.rs : Use error code range 20000-20015 for AccountError variants
Applied to files:
sdk-libs/token-sdk/src/error.rs
📚 Learning: 2026-01-14T00:07:21.335Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: DOCS.md:0-0
Timestamp: 2026-01-14T00:07:21.335Z
Learning: For Solana standard ProgramError variants, document with their actual codes: InvalidInstructionData = 3, InvalidAccountData = 4, InsufficientFunds = 6, MissingRequiredSignature = 8, NotEnoughAccountKeys = 11, InvalidSeeds = 14
Applied to files:
sdk-libs/token-sdk/src/error.rs
📚 Learning: 2025-11-24T17:56:50.011Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/batched-merkle-tree/docs/INITIALIZE_STATE_TREE.md:0-0
Timestamp: 2025-11-24T17:56:50.011Z
Learning: Applies to program-libs/batched-merkle-tree/docs/src/initialize_state_tree.rs : Return error `AccountError::InvalidAccountSize` (error code 12006) when account data length doesn't match calculated size requirements
Applied to files:
sdk-libs/token-sdk/src/error.rs
📚 Learning: 2026-01-14T00:05:32.217Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-tests/sdk-light-token-test/README.md:0-0
Timestamp: 2026-01-14T00:05:32.217Z
Learning: Applies to sdk-tests/sdk-light-token-test/**/*.rs : Use the builder pattern from `light-token-sdk::ctoken` module for CPI operations instead of manual instruction building
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-11T01:05:19.378Z
Learnt from: CR
Repo: Lightprotocol/distributor PR: 0
File: programs/merkle-distributor/CLAUDE.md:0-0
Timestamp: 2026-01-11T01:05:19.378Z
Learning: Applies to programs/merkle-distributor/**/instructions/{new_claim,claim_locked}.rs : Use Light SDK v2 CPI via `LightSystemProgramCpi::new_cpi` for compressed account interactions
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-14T00:06:46.444Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/compressed-token/program/CLAUDE.md:0-0
Timestamp: 2026-01-14T00:06:46.444Z
Learning: Applies to programs/compressed-token/program/src/**/*.rs : When transferring lamports programmatically, use safe transfer helpers from `shared/transfer_lamports.rs`
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-14T00:06:46.444Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/compressed-token/program/CLAUDE.md:0-0
Timestamp: 2026-01-14T00:06:46.444Z
Learning: Data structures must be isolated in the `light-token-interface` crate (program-libs/token-interface/) so SDKs and clients can import types without pulling in program dependencies
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-14T00:06:46.444Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/compressed-token/program/CLAUDE.md:0-0
Timestamp: 2026-01-14T00:06:46.444Z
Learning: Applies to programs/compressed-token/program/src/compressed_token/transfer2/**/*.rs : Transfer2 instruction must perform sum checks when supporting multi-mint Compress, Decompress, and CompressAndClose operations
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-14T00:05:32.217Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-tests/sdk-light-token-test/README.md:0-0
Timestamp: 2026-01-14T00:05:32.217Z
Learning: Applies to sdk-tests/sdk-light-token-test/**/*.rs : Document each instruction implementation with clear comments explaining the builder pattern usage and account structure
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2025-11-24T17:59:36.701Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/account-checks/docs/DISCRIMINATOR.md:0-0
Timestamp: 2025-11-24T17:59:36.701Z
Learning: Applies to program-libs/account-checks/docs/**/account-checks/**/*.rs : Implement the Discriminator trait for account types, providing 8-byte LIGHT_DISCRIMINATOR constant and LIGHT_DISCRIMINATOR_SLICE reference in Rust account structures
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-15T02:04:37.090Z
Learnt from: CR
Repo: Lightprotocol/program-examples PR: 0
File: zk/zk-id/README.md:0-0
Timestamp: 2026-01-15T02:04:37.090Z
Learning: Applies to zk/zk-id/src/lib.rs : Use CpiAccounts::new() from light_sdk::cpi::v2 for account parameter handling
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-14T00:05:32.217Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-tests/sdk-light-token-test/README.md:0-0
Timestamp: 2026-01-14T00:05:32.217Z
Learning: Applies to sdk-tests/sdk-light-token-test/**/*.rs : Use the `invoke()` method for regular CPI calls where the program acts as authority in compressed token operations
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2025-11-24T17:59:23.357Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/account-checks/docs/CLAUDE.md:0-0
Timestamp: 2025-11-24T17:59:23.357Z
Learning: Applies to program-libs/account-checks/docs/src/**/*.rs : Use 8-byte discriminators for account type identification and implement the Discriminator trait for account identification
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-14T00:06:46.444Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/compressed-token/program/CLAUDE.md:0-0
Timestamp: 2026-01-14T00:06:46.444Z
Learning: Applies to programs/compressed-token/program/src/**/*.rs : When calculating rent top-ups for compressible accounts, use utilities from `shared/compressible_top_up.rs`
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2025-11-24T18:02:15.670Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:15.670Z
Learning: Applies to programs/registry/src/account_compression_cpi/*.rs : Create wrapper instruction module at `src/account_compression_cpi/new_operation.rs` with `NewOperationContext` struct defining required accounts
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-14T00:05:32.217Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-tests/sdk-light-token-test/README.md:0-0
Timestamp: 2026-01-14T00:05:32.217Z
Learning: Implement all 8 compressed token instructions: create_cmint, mint_to_ctoken, create_token_account_invoke, create_token_account_invoke_signed, create_ata_invoke, create_ata_invoke_signed, transfer_interface_invoke, and transfer_interface_invoke_signed
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2025-11-24T17:58:50.237Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/account-checks/docs/ACCOUNT_CHECKS.md:0-0
Timestamp: 2025-11-24T17:58:50.237Z
Learning: Applies to program-libs/account-checks/docs/program-libs/account-checks/src/checks.rs : Use generic `AccountInfoTrait` parameter for all account validation functions to enable compatibility with both Solana and Pinocchio runtimes
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2025-11-24T17:59:03.485Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/account-checks/docs/ACCOUNT_INFO_TRAIT.md:0-0
Timestamp: 2025-11-24T17:59:03.485Z
Learning: Applies to program-libs/account-checks/docs/program-libs/account-checks/src/account_info/{solana,pinocchio}.rs : Implement AccountInfoTrait with SDK-specific Pubkey types: `solana_pubkey::Pubkey` for solana-program feature and `[u8; 32]` raw bytes for pinocchio feature
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-10T19:26:10.578Z
Learnt from: CR
Repo: Lightprotocol/program-examples PR: 0
File: airdrop-implementations/simple-claim/CLAUDE.md:0-0
Timestamp: 2026-01-10T19:26:10.578Z
Learning: Applies to airdrop-implementations/simple-claim/program/src/instruction.rs : Define ClaimAccounts structure with 16 account fields in order: claimant, fee_payer, associated_airdrop_pda, ctoken_cpi_authority_pda, light_system_program, registered_program_pda, noop_program, account_compression_authority, account_compression_program, ctoken_program, spl_interface_pda, decompress_destination, token_program, system_program, state_tree, and queue
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-14T00:06:11.915Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/CLAUDE.md:0-0
Timestamp: 2026-01-14T00:06:11.915Z
Learning: Applies to program-libs/compressible/src/config.rs : CompressibleConfig account structure must support multiple serialization features (Anchor, Pinocchio, Borsh) for program compatibility
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-14T00:05:47.820Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/compressible/docs/CONFIG_ACCOUNT.md:0-0
Timestamp: 2026-01-14T00:05:47.820Z
Learning: Applies to program-libs/compressible/docs/**/*.rs : CompressibleConfig account state layout must follow the defined structure with version (u16), state (u8), bump (u8), update_authority (Pubkey), withdrawal_authority (Pubkey), rent_sponsor (Pubkey), compression_authority (Pubkey), rent_sponsor_bump (u8), compression_authority_bump (u8), rent_config (RentConfig), address_space ([Pubkey; 4]), and _place_holder ([u8; 32]) fields
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2025-11-24T17:59:03.485Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/account-checks/docs/ACCOUNT_INFO_TRAIT.md:0-0
Timestamp: 2025-11-24T17:59:03.485Z
Learning: Applies to program-libs/account-checks/docs/program-libs/account-checks/src/account_info/test_account_info.rs : Create a test-only AccountInfo mock implementation without external dependencies for unit testing AccountInfoTrait implementations
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2025-11-24T17:59:03.485Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/account-checks/docs/ACCOUNT_INFO_TRAIT.md:0-0
Timestamp: 2025-11-24T17:59:03.485Z
Learning: Applies to program-libs/account-checks/docs/program-libs/account-checks/src/account_info/*.rs : AccountInfoTrait implementations must return `AccountError` from all fallible operations: `BorrowAccountDataFailed` (12009) for borrow failures, `InvalidSeeds` (12016) for PDA creation, and `FailedBorrowRentSysvar` (12014) for rent access
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2025-11-24T17:58:50.237Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: program-libs/account-checks/docs/ACCOUNT_CHECKS.md:0-0
Timestamp: 2025-11-24T17:58:50.237Z
Learning: Applies to program-libs/account-checks/docs/program-libs/account-checks/src/checks.rs : Implement `check_pda_seeds_with_bump` function to verify PDA with known bump seed using `create_program_address`, returning `InvalidSeeds` (20010) error on mismatch
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-10T19:26:10.578Z
Learnt from: CR
Repo: Lightprotocol/program-examples PR: 0
File: airdrop-implementations/simple-claim/CLAUDE.md:0-0
Timestamp: 2026-01-10T19:26:10.578Z
Learning: Applies to airdrop-implementations/simple-claim/program/src/processor.rs : Airdrop PDA must be derived using seeds: [claimant.to_bytes(), mint.to_bytes(), unlock_slot.to_le_bytes(), bump] via Pubkey::create_program_address
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-14T00:05:32.217Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-tests/sdk-light-token-test/README.md:0-0
Timestamp: 2026-01-14T00:05:32.217Z
Learning: Applies to sdk-tests/sdk-light-token-test/**/*.rs : Use the `invoke_signed()` method for PDA-signed CPI calls in compressed token operations
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2026-01-10T19:26:38.625Z
Learnt from: CR
Repo: Lightprotocol/program-examples PR: 0
File: create-and-update/CLAUDE.md:0-0
Timestamp: 2026-01-10T19:26:38.625Z
Learning: Applies to create-and-update/**/programs/**/src/**/*.rs : Derive `LIGHT_CPI_SIGNER` using the `derive_light_cpi_signer!` macro from program ID for CPI authorization
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
📚 Learning: 2025-11-24T18:02:15.670Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: programs/registry/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:02:15.670Z
Learning: Applies to programs/registry/src/account_compression_cpi/*.rs : Implement `process_new_operation()` function in wrapper module to handle PDA signer setup, account mapping, and CPI execution
Applied to files:
sdk-libs/token-sdk/src/token/transfer_interface.rs
🧬 Code graph analysis (1)
sdk-libs/token-sdk/src/token/transfer_interface.rs (1)
sdk-libs/token-sdk/src/utils.rs (1)
is_light_token_owner(25-40)
⏰ 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). (20)
- GitHub Check: stateless-js-v2
- GitHub Check: Test program-libs-fast
- GitHub Check: Test program-libs-slow
- GitHub Check: Test batched-merkle-tree-simulate
- GitHub Check: lint
- GitHub Check: programs (compressed-token-and-e2e, ["cargo test -p light-compressed-token", "cargo-test-sbf -p c...
- GitHub Check: programs (account-compression-and-registry, ["cargo-test-sbf -p account-compression-test", "cargo...
- 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 (compressed-token-batched-tree, ["cargo-test-sbf -p compressed-token-test -- test_transf...
- GitHub Check: system-programs (native, ["cargo-test-sbf -p sdk-native-test", "cargo-test-sbf -p sdk-v1-native-t...
- GitHub Check: programs (system-cpi-test, ["cargo-test-sbf -p system-cpi-test", "cargo test -p light-system-prog...
- GitHub Check: programs (light-system-program-address, ["cargo-test-sbf -p system-test -- test_with_address", "c...
- GitHub Check: cli-v1
- GitHub Check: stateless-js-v1
- GitHub Check: system-programs (token test, ["cargo-test-sbf -p sdk-token-test"])
- GitHub Check: Forester e2e test
- GitHub Check: system-programs (anchor & pinocchio, ["cargo-test-sbf -p sdk-anchor-test", "cargo-test-sbf -p sdk...
- GitHub Check: system-programs (sdk-libs, light-sdk-macros light-sdk light-program-test light-client light-token...
- GitHub Check: cli-v2
🔇 Additional comments (3)
sdk-libs/token-sdk/src/error.rs (1)
78-79: Looks good — new error variant is consistently wired.Enum variant, display message, and numeric mapping are aligned and follow the existing error-code pattern.
Also applies to: 141-141
sdk-libs/token-sdk/src/token/transfer_interface.rs (2)
57-77: SplInterface CPI → Pubkey mapping looks solid.Clean conversion and keeps CPI lifetime details out of the public interface.
292-324: CPI builder argument validation is clear.
with_spl_interfaceenforces required accounts and fails fast with precise errors.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
ff14aea to
21a7d1f
Compare
revert photon api renamings cleanup feat: transfer interface spl -> spl , t22 -> t22 transfer support
21a7d1f to
341fced
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (21)
sdk-libs/token-client/src/instructions/update_compressed_mint.rs (2)
85-92: Don’t default missing compressed mint address to zero.
A zero address can silently build an invalid proof or target the wrong account. Treat a missing address as an error.🐛 Proposed fix
- let compressed_mint_inputs = MintWithContext { + let compressed_mint_address = compressed_mint_account + .address + .ok_or_else(|| RpcError::CustomError("Compressed mint address missing".to_string()))?; + + let compressed_mint_inputs = MintWithContext { leaf_index: compressed_mint_leaf_index, prove_by_index: true, // Use index-based proof like mint_to_compressed root_index: 0, // Use 0 like mint_to_compressed - address: compressed_mint_account.address.unwrap_or([0u8; 32]), + address: compressed_mint_address, mint: Some(compressed_mint_instruction_data), };
95-105: Fix output queue selection to keep updated mint in its source tree.
The comment "Use same queue for output" is misleading. The code currently usesstate_tree_info.queue(a random state tree), but the updated mint should stay in its source tree's output queue for consistency withmint_to_compressedbehavior, where mint objects always go tocompressed_mint_account.tree_info.queue.Suggested fix
- out_output_queue: state_tree_info.queue, // Use same queue for output + out_output_queue: compressed_mint_account.tree_info.queue,sdk-libs/program-test/src/compressible.rs (1)
33-80: Size-based account type detection will fail for Token-2022 Mint accounts.The 165-byte offset cannot reliably distinguish Token from Mint accounts because Token-2022 supports variable-length accounts with TLV extensions. Mint accounts are typically 82 bytes but can exceed 165 bytes with extensions, causing misclassification or silent failure. The try-parse approach (Token first, then Mint) is sound and avoids this pitfall.
Alternatively, if
spl_token_2022::extension::StateWithExtensionsis available in your dependencies, that's the canonical path:StateWithExtensions::<Mint>::unpack(data)?andStateWithExtensions::<Account>::unpack(data)?handle all extension cases safely.🔧 Suggested refactor (try-based approach)
-fn determine_account_type(data: &[u8]) -> Option<u8> { - const ACCOUNT_TYPE_OFFSET: usize = 165; - - match data.len().cmp(&ACCOUNT_TYPE_OFFSET) { - std::cmp::Ordering::Less => None, - std::cmp::Ordering::Equal => Some(ACCOUNT_TYPE_TOKEN_ACCOUNT), // 165 bytes = Token - std::cmp::Ordering::Greater => Some(data[ACCOUNT_TYPE_OFFSET]), - } -} - #[cfg(feature = "devenv")] fn extract_compression_info(data: &[u8]) -> Option<(CompressionInfo, u8, bool)> { use light_zero_copy::traits::ZeroCopyAt; - let account_type = determine_account_type(data)?; - - match account_type { - ACCOUNT_TYPE_TOKEN_ACCOUNT => { - let (ctoken, _) = Token::zero_copy_at(data).ok()?; - let ext = ctoken.get_compressible_extension()?; - // ... extract compression info ... - Some((compression_info, account_type, compression_only)) - } - ACCOUNT_TYPE_MINT => { - let mint = Mint::deserialize(&mut &data[..]).ok()?; - Some((mint.compression, account_type, false)) - } - _ => None, - } + if let Ok((ctoken, _)) = Token::zero_copy_at(data) { + let ext = ctoken.get_compressible_extension()?; + // ... extract compression info ... + return Some((compression_info, ACCOUNT_TYPE_TOKEN_ACCOUNT, compression_only)); + } + + let mint = Mint::deserialize(&mut &data[..]).ok()?; + Some((mint.compression, ACCOUNT_TYPE_MINT, false)) }programs/compressed-token/program/src/compressible/claim.rs (1)
147-154: Renamecminttomintfor clarity after the type rename.This reduces cognitive load now that the type is
Mint.♻️ Suggested rename
- let (mut cmint, _) = Mint::zero_copy_at_mut_checked(&mut account_data)?; - cmint + let (mut mint, _) = Mint::zero_copy_at_mut_checked(&mut account_data)?; + mint .base .compression .claim_and_update(claim_and_update)programs/compressed-token/program/src/compressed_token/mint_action/actions/update_metadata.rs (1)
15-51: Type updated to&mut Mint; consider renaming parameter.The function correctly accepts
&mut Mintnow. The parameter namecompressed_mintis slightly inconsistent with the newMinttype—consider renaming to justmintfor consistency, though this is a minor nitpick since it's an internal function.♻️ Optional parameter rename
fn get_metadata_extension_mut<'a>( - compressed_mint: &'a mut Mint, + mint: &'a mut Mint, extension_index: usize, operation_name: &str, signer: &pinocchio::pubkey::Pubkey, ) -> Result<&'a mut TokenMetadata, ProgramError> { - let extensions = compressed_mint.extensions.as_mut().ok_or_else(|| { + let extensions = mint.extensions.as_mut().ok_or_else(|| {programs/compressed-token/program/src/shared/compressible_top_up.rs (1)
18-56: Consider updating doc comments and parameter names to Mint terminology.While the import and call site were updated, the documentation and parameter names still reference the old "CMint" terminology:
- Line 18-24: Doc comments mention "CMint" and "CToken"
- Line 30: Parameter named
cmint- Line 51: Comment says "CMint top-up"
For consistency with the PR's renaming effort, consider updating these as well.
♻️ Suggested terminology updates
-/// Calculate and execute top-up transfers for compressible CMint and CToken accounts. -/// CMint always has compression info. CToken requires Compressible extension or errors. +/// Calculate and execute top-up transfers for compressible Mint and CToken accounts. +/// Mint always has compression info. CToken requires Compressible extension or errors. /// /// # Arguments -/// * `cmint` - The CMint account (may or may not have Compressible extension) +/// * `mint` - The Mint account (always has compression info) /// * `ctoken` - The CToken account (may or may not have Compressible extension) /// * `payer` - The fee payer for top-ups /// * `max_top_up` - Maximum lamports for top-ups combined (0 = no limit) #[inline(always)] #[profile] #[allow(unused)] pub fn calculate_and_execute_compressible_top_ups<'a>( - cmint: &'a AccountInfo, + mint: &'a AccountInfo, ctoken: &'a AccountInfo, @@ let mut transfers = [ Transfer { - account: cmint, + account: mint, amount: 0, }, @@ - // Calculate CMint top-up using optimized function (owner check inside) + // Calculate Mint top-up using optimized function (owner check inside) #[cfg(target_os = "solana")] - if let Some(amount) = mint_top_up_lamports_from_account_info(cmint, &mut current_slot) { + if let Some(amount) = mint_top_up_lamports_from_account_info(mint, &mut current_slot) {programs/compressed-token/program/src/compressed_token/mint_action/mint_output.rs (1)
26-26: Minor: Comment still references "CMint account".The comment on line 26 says "writes mint data to CMint account" — consider updating to "writes mint data to decompressed Mint account" or similar for consistency with the broader rename.
📝 Suggested comment update
/// Processes the output compressed mint account. -/// When decompressed, writes mint data to CMint account (compressed account is empty). +/// When decompressed, writes mint data to decompressed Mint account (compressed account is empty). #[profile]sdk-libs/compressible-client/src/decompress_mint.rs (3)
1-13: Module documentation still uses outdated "CMint" terminology.The doc comments reference "CMint" throughout (lines 1, 4, etc.), but this PR renames
CompressedMinttoMint. For consistency, these should be updated:
- Line 1: "CMint accounts" → "compressed mint accounts" or just "Mint accounts"
- Line 4: "CMint accounts (mints created via..." → "mint accounts..."
- Similar references in lines 52, 56, 58, 63, 67
This is a minor documentation issue but worth addressing to avoid confusion for future readers.
74-85: Struct fieldcmintshould be renamed tomintfor consistency.The
MintInterfacestruct still usescmintas a field name (line 76), while the PR's intent is to move away from the "cmint" nomenclature. Similarly, comments reference "CMint PDA pubkey" on line 75.♻️ Suggested rename
pub struct MintInterface { - /// The CMint PDA pubkey. - pub cmint: Pubkey, - /// The mint signer pubkey (used to derive CMint). + /// The Mint PDA pubkey. + pub mint: Pubkey, + /// The mint signer pubkey (used to derive Mint). pub signer: Pubkey,
320-332: Duplicate step number in comments.Lines 329-332 have step "5. Check if already decompressed..." but then line 334 also says "5. Get validity proof". The second should be step 6.
♻️ Fix step numbering
// 5. Check if already decompressed flag is set - return empty vec (idempotent) if mint_data.metadata.mint_decompressed { return Ok(vec![]); } - // 5. Get validity proof + // 6. Get validity proof let proof_result = indexersdk-libs/program-test/src/program_test/light_program_test.rs (1)
628-634: Doc comments still reference outdated "CMint" terminology.The documentation on lines 632-634 still uses "CMint" while the code has been updated to use "Mint". For consistency with the rename effort, consider updating these comments.
Suggested fix
/// Fetches MintInterface for a mint signer pubkey. /// /// Checks on-chain first, then compressed state. /// Returns `MintInterface` with state: - /// - `Hot` if CMint exists on-chain - /// - `Cold` if CMint is compressed (needs decompression) - /// - `None` if CMint doesn't exist + /// - `Hot` if Mint exists on-chain + /// - `Cold` if Mint is compressed (needs decompression) + /// - `None` if Mint doesn't existprograms/compressed-token/program/src/compressed_token/mint_action/zero_copy_config.rs (1)
36-42: Comment still references "CMint" terminology.Line 37 mentions "Get extensions from instruction data or CMint account" — this should be updated to "Mint" for consistency with the rename.
// Generate output config based on final state after all actions - // Get extensions from instruction data or CMint account + // Get extensions from instruction data or Mint accountprograms/compressed-token/program/src/compressed_token/mint_action/actions/decompress_mint.rs (2)
25-36: Comments still reference outdated "CMint" terminology.The docstring mentions "CMint Solana account" (line 25) and "Set cmint_decompressed flag" (line 36), but the code now uses
Minttypes andmint_decompressedfield. Update for consistency:-/// Processes the DecompressMint action by creating a CMint Solana account +/// Processes the DecompressMint action by creating a Mint Solana account /// from a compressed mint. /// /// ## Process Steps /// ... -/// 8. **Flag Update**: Set cmint_decompressed flag +/// 8. **Flag Update**: Set mint_decompressed flag
122-126: Comment and error message reference "CMint" terminology.- // 6b. Verify CMint account matches compressed_mint.metadata.mint - if !pubkey_eq(cmint.key(), &compressed_mint.metadata.mint.to_bytes()) { - msg!("CMint account does not match compressed_mint.metadata.mint"); + // 6b. Verify Mint account matches compressed_mint.metadata.mint + if !pubkey_eq(mint_account.key(), &compressed_mint.metadata.mint.to_bytes()) { + msg!("Mint account does not match compressed_mint.metadata.mint"); return Err(ErrorCode::InvalidCMintAccount.into());programs/compressed-token/program/src/compressed_token/mint_action/actions/process_actions.rs (1)
146-152: Enum variant renamed but function call uses old name.The match arm correctly uses
ZAction::CompressAndCloseMint(line 146), but the function being called is stillprocess_compress_and_close_cmint_action(line 147). If the function was renamed as part of this PR (consistent with the file rename mentioned in PR description), this call should be updated:ZAction::CompressAndCloseMint(action) => { - process_compress_and_close_cmint_action( + process_compress_and_close_mint_action( action, compressed_mint, validated_accounts, )?; }programs/compressed-token/program/src/compressed_token/mint_action/actions/compress_and_close_cmint.rs (1)
16-32: Doc comments still reference "CMint" terminology.The function documentation extensively references "CMint" (e.g., "CMint doesn't exist", "CMint account matches", "CMint Solana account") while the code now uses
Minttypes. Consider updating the doc comments for consistency with the Mint terminology rename. For example:
- Line 16: "CMint Solana account" → "Mint Solana account"
- Line 20: "CMint doesn't exist" → "Mint doesn't exist"
- Line 22: "CMint account" → "Mint account"
- Line 27: "CMint" → "Mint" throughout
This isn't a functional issue but would improve documentation consistency.
program-libs/token-interface/tests/compressed_mint.rs (1)
49-108: Optional: rename helper to match Mint terminology.The helper now returns
Mint; renaming reduces legacy “compressed” naming.♻️ Suggested rename
-/// Generate a random Mint for testing -fn generate_random_compressed_mint(rng: &mut impl Rng, with_extensions: bool) -> Mint { +/// Generate a random Mint for testing +fn generate_random_mint(rng: &mut impl Rng, with_extensions: bool) -> Mint { @@ - let original_mint = generate_random_compressed_mint(&mut rng, false); + let original_mint = generate_random_mint(&mut rng, false);programs/compressed-token/program/tests/mint_action.rs (1)
225-252: Optional: rename localcmint_decompressedtomint_decompressed.Keeps variable naming aligned with the Mint rename while leaving the struct field name intact.
♻️ Suggested rename
- let cmint_decompressed = data.mint.as_ref().unwrap().metadata.mint_decompressed; + let mint_decompressed = data.mint.as_ref().unwrap().metadata.mint_decompressed; @@ - cmint_decompressed, + cmint_decompressed: mint_decompressed,sdk-libs/token-sdk/src/token/decompress_mint.rs (3)
237-267: Inconsistent naming:DecompressCMintWithCpiContextstill uses "CMint".This struct name still contains "CMint" while the rest of the file uses "Mint" terminology. The comment on line 239 also says "CMint PDA". For consistency with the PR's renaming objective, consider renaming to
DecompressMintWithCpiContext.Similarly, the local variable
cmint_pdaon line 272 and the method callfind_mint_addresscould be reviewed for consistency.♻️ Suggested rename
-pub struct DecompressCMintWithCpiContext { - /// Mint seed pubkey (used to derive CMint PDA) +pub struct DecompressMintWithCpiContext { + /// Mint seed pubkey (used to derive Mint PDA) pub mint_seed_pubkey: Pubkey,
316-352: Inconsistent naming:DecompressCMintCpiWithContextandcmintfield.This CPI struct retains "CMint" in the name and has a field
pub cmint: AccountInfo<'info>(line 324). For consistency:
- Rename struct to
DecompressMintCpiWithContext- Rename field
cminttomint- Update the doc comment on line 323
♻️ Suggested rename
-pub struct DecompressCMintCpiWithContext<'info> { +pub struct DecompressMintCpiWithContext<'info> { /// Mint seed account (used to derive CMint PDA, does not sign) pub mint_seed: AccountInfo<'info>, /// Mint authority (must sign) pub authority: AccountInfo<'info>, /// Fee payer pub payer: AccountInfo<'info>, - /// CMint PDA account (writable) - pub cmint: AccountInfo<'info>, + /// Mint PDA account (writable) + pub mint: AccountInfo<'info>,
387-407:build_account_infosstill referencesself.cmint.Line 393 uses
self.cmint.clone()which would need to change if the field is renamed tomint.
🤖 Fix all issues with AI agents
In
`@programs/compressed-token/program/src/compressed_token/mint_action/mint_input.rs`:
- Around line 30-31: Update the stale comment in mint_input.rs that reads "When
CMint was decompressed (input state BEFORE actions), use zero values" to use the
new terminology "Mint" instead of "CMint"; locate the conditional using
accounts_config.cmint_decompressed and revise the comment above the let
(discriminator, input_data_hash) = if accounts_config.cmint_decompressed { ... }
accordingly so the comment matches the rename.
In
`@programs/compressed-token/program/src/compressed_token/mint_action/processor.rs`:
- Around line 54-68: Comments and variable names still use "cmint/CMint" while
the type calls now use Mint (Mint::try_from, Mint::from_account_info_checked);
align terminology by renaming comments and identifiers for clarity: update
comments that mention "CMint is decompressed" to "decompressed mint" (or
similar), rename the boolean accounts_config.cmint_decompressed to
accounts_config.mint_decompressed (or accounts_config.decompressed_mint), rename
validated_accounts.get_cmint() to get_mint_account (or
get_decompressed_mint_account) and cmint_account to mint_account, and adjust any
related error names/messages (e.g., ErrorCode::MintActionMissingCMintAccount) so
names consistently reference "mint" rather than "cmint" across this block and
associated definitions.
In
`@programs/compressed-token/program/src/compressed_token/mint_action/zero_copy_config.rs`:
- Line 27: Rename the parameter named "cmint" to "mint" in the function
signature where it is declared as "&Mint" and update every usage of the old
identifier "cmint" within the same file to "mint" (including the places that
currently reference cmint on the other lines referenced in the review). Ensure
the parameter name change preserves borrows/mutability (e.g., &Mint stays &Mint)
and update any pattern matches or method calls that used "cmint" to use "mint"
so identifiers are consistent with the renamed type.
In `@sdk-libs/token-client/src/instructions/update_compressed_mint.rs`:
- Around line 71-80: The code unnecessarily clones compressed_mint before
calling MintInstructionData::try_from; change the call to consume the owned
compressed_mint (pass compressed_mint directly to MintInstructionData::try_from)
instead of compressed_mint.clone(), ensuring no further use of compressed_mint
after that point (or update subsequent code to use the resulting
MintInstructionData); locate this in the block where BorshDeserialize produces
compressed_mint and replace the clone usage so the value is moved into
MintInstructionData::try_from.
In `@sdk-libs/token-sdk/src/token/transfer_interface.rs`:
- Around line 404-468: The code calls determine_transfer_type twice (once
explicitly and again indirectly when building the instruction), so change
invoke_signed to compute transfer_type once and reuse it when building the
instruction: call determine_transfer_type(self.source_account.owner,
self.destination_account.owner) and store the result in transfer_type, then
generate the instruction using a new or modified method that accepts the
already-determined TransferType (e.g., add an instruction_for(&self,
transfer_type: TransferType) or change instruction(&self) to accept
transfer_type) and use transfer_type in the match arms
(TransferType::LightToLight, LightToSpl, SplToLight, SplToSpl) to avoid the
duplicate call.
♻️ Duplicate comments (8)
sdk-libs/token-sdk/src/compressed_token/v2/mint_to_compressed/instruction.rs (1)
16-34: Field name still carries “compressed” after type rename.
Line 19 keepscompressed_mint_inputseven though the type is nowMintWithContext. Consider renaming for API consistency (same as earlier feedback).sdk-libs/token-client/src/instructions/create_mint.rs (1)
38-63: Verify address-tree source and empty-actions validity in MintAction.
Ifcreate_mint_action_instructionalso fetches the address tree, the derivedcompressed_mint_addresscan drift on tree rotation; also confirm the on-chain MintAction path accepts an emptyactionsvec for create-only. Consider plumbing the tree into the builder or deriving there to keep a single source of truth.#!/bin/bash # Inspect MintAction builder for address-tree fetching and actions validation. fd -a 'mint_action.rs' sdk-libs -x rg -n "create_mint_action_instruction|get_address_tree_v2|actions|MintActionParams|NewMint" {} # Inspect on-chain MintAction handling for empty actions / create-only behavior. rg -n "MintAction|actions|CreateCompressedMint|DecompressMint|NewMint" \ programs/compressed-token/program/src/compressed_token/mint_action -g '*.rs'program-libs/token-interface/src/state/mint/top_up.rs (1)
11-13: Constant renamed; backward compatibility consideration already noted.The constant rename from
CMINT_MIN_SIZE_WITH_COMPRESSIONtoMINT_MIN_SIZE_WITH_COMPRESSIONis consistent with the PR's goals. A previous review already suggested adding a deprecated alias for backward compatibility.program-libs/token-interface/tests/hash_tests.rs (1)
1-10: Hash collision tests remain commented out - this is a security coverage gap.The entire test module (451 lines) testing
Mint::hash()is commented out. While the type renames within the comments (Mint,MintMetadata,mint_decompressed) are correct, the tests themselves provide zero coverage because they're disabled.These tests verify critical security properties:
- Hash determinism
- No collisions across field variations
- Authority confusion prevention (None vs Some(zero_pubkey))
- Boundary value handling
Hash collision bugs in compressed account hashing could allow attackers to forge valid proofs. The implementation exists and appears functional based on the learnings, but without active tests there's no CI verification.
Recommendation: Uncomment these tests and resolve any compilation issues. The type names have been updated correctly in the comments, so the tests should be close to compiling with the new
Mint/MintMetadatatypes.sdk-libs/token-sdk/src/token/create_mint.rs (2)
34-39: Still missing client‑side guard forrent_payment(0 or ≥2).Docs promise a constraint, but callers can still pass invalid values without an early error.
335-358: Missing CPI key validations still outstanding.
TryFromstill only checksmint_authority; add guards forparams.mint,compressible_config, andrent_sponsorto prevent mismatched CPI accounts.sdk-libs/token-sdk/src/token/transfer_interface.rs (2)
205-220:max_top_up: Nonein CPI conversion - intentional limitation.As noted in a previous review, the
From<&TransferInterfaceCpi>implementation hardcodesmax_top_up: NonebecauseTransferInterfaceCpilacks this field. If CPI callers should have this control for LightToLight transfers, consider adding the field. Otherwise, document this limitation.
334-398:invoke()method - transfer type computed twice.Looking at the implementation:
- Line 337-338:
determine_transfer_typecalled explicitly- Line 339:
self.instruction()internally callsdetermine_transfer_typeagain viaTransferInterface::from(self).instruction()(line 328 → 131)This results in redundant computation. The previous review comment was marked as "addressed" but the code still shows the double call pattern.
♻️ Suggested optimization
Compute
transfer_typeonce and pass it through, or refactorinstruction()to accept an optional pre-computed type:pub fn invoke(self) -> Result<(), ProgramError> { use solana_cpi::invoke; let transfer_type = determine_transfer_type(self.source_account.owner, self.destination_account.owner)?; - let instruction = self.instruction()?; + let transfer_interface = TransferInterface::from(&self); + // Use transfer_type directly in a match that builds the instruction + // to avoid re-computing it inside instruction()
| // When CMint was decompressed (input state BEFORE actions), use zero values | ||
| let (discriminator, input_data_hash) = if accounts_config.cmint_decompressed { |
There was a problem hiding this comment.
Stale terminology in comment: "CMint" should be "Mint".
The comment on line 30 still references "CMint" which is inconsistent with the broader rename effort in this PR.
Suggested fix
- // When CMint was decompressed (input state BEFORE actions), use zero values
+ // When Mint was decompressed (input state BEFORE actions), use zero values📝 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.
| // When CMint was decompressed (input state BEFORE actions), use zero values | |
| let (discriminator, input_data_hash) = if accounts_config.cmint_decompressed { | |
| // When Mint was decompressed (input state BEFORE actions), use zero values | |
| let (discriminator, input_data_hash) = if accounts_config.cmint_decompressed { |
🤖 Prompt for AI Agents
In
`@programs/compressed-token/program/src/compressed_token/mint_action/mint_input.rs`
around lines 30 - 31, Update the stale comment in mint_input.rs that reads "When
CMint was decompressed (input state BEFORE actions), use zero values" to use the
new terminology "Mint" instead of "CMint"; locate the conditional using
accounts_config.cmint_decompressed and revise the comment above the let
(discriminator, input_data_hash) = if accounts_config.cmint_decompressed { ... }
accordingly so the comment matches the rename.
programs/compressed-token/program/src/compressed_token/mint_action/processor.rs
Show resolved
Hide resolved
| parsed_instruction_data: &ZMintActionCompressedInstructionData<'_>, | ||
| accounts_config: &AccountsConfig, | ||
| cmint: &CompressedMint, | ||
| cmint: &Mint, |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider renaming parameter cmint to mint for consistency.
Throughout this PR, the type has been renamed from CompressedMint to Mint. The parameter name here still uses the abbreviated old convention. For consistency with the broader rename, consider:
- cmint: &Mint,
+ mint: &Mint,This would require updating references on lines 40 and 88 as well.
🤖 Prompt for AI Agents
In
`@programs/compressed-token/program/src/compressed_token/mint_action/zero_copy_config.rs`
at line 27, Rename the parameter named "cmint" to "mint" in the function
signature where it is declared as "&Mint" and update every usage of the old
identifier "cmint" within the same file to "mint" (including the places that
currently reference cmint on the other lines referenced in the review). Ensure
the parameter name change preserves borrows/mutability (e.g., &Mint stays &Mint)
and update any pattern matches or method calls that used "cmint" to use "mint"
so identifiers are consistent with the renamed type.
| let compressed_mint: Mint = | ||
| BorshDeserialize::deserialize(&mut compressed_mint_data.data.as_slice()).map_err(|e| { | ||
| RpcError::CustomError(format!("Failed to deserialize compressed mint: {}", e)) | ||
| })?; | ||
|
|
||
| // Convert to instruction data format | ||
| let compressed_mint_instruction_data = | ||
| CompressedMintInstructionData::try_from(compressed_mint.clone()).map_err(|e| { | ||
| RpcError::CustomError(format!("Failed to convert compressed mint: {:?}", e)) | ||
| })?; | ||
| let compressed_mint_instruction_data = MintInstructionData::try_from(compressed_mint.clone()) | ||
| .map_err(|e| { | ||
| RpcError::CustomError(format!("Failed to convert compressed mint: {:?}", e)) | ||
| })?; |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Avoid the extra clone when converting MintInstructionData.
compressed_mint isn’t used after conversion, so you can move it to avoid an unnecessary allocation.
♻️ Proposed diff
- let compressed_mint_instruction_data = MintInstructionData::try_from(compressed_mint.clone())
+ let compressed_mint_instruction_data = MintInstructionData::try_from(compressed_mint)
.map_err(|e| {
RpcError::CustomError(format!("Failed to convert compressed mint: {:?}", e))
})?;📝 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.
| let compressed_mint: Mint = | |
| BorshDeserialize::deserialize(&mut compressed_mint_data.data.as_slice()).map_err(|e| { | |
| RpcError::CustomError(format!("Failed to deserialize compressed mint: {}", e)) | |
| })?; | |
| // Convert to instruction data format | |
| let compressed_mint_instruction_data = | |
| CompressedMintInstructionData::try_from(compressed_mint.clone()).map_err(|e| { | |
| RpcError::CustomError(format!("Failed to convert compressed mint: {:?}", e)) | |
| })?; | |
| let compressed_mint_instruction_data = MintInstructionData::try_from(compressed_mint.clone()) | |
| .map_err(|e| { | |
| RpcError::CustomError(format!("Failed to convert compressed mint: {:?}", e)) | |
| })?; | |
| let compressed_mint: Mint = | |
| BorshDeserialize::deserialize(&mut compressed_mint_data.data.as_slice()).map_err(|e| { | |
| RpcError::CustomError(format!("Failed to deserialize compressed mint: {}", e)) | |
| })?; | |
| // Convert to instruction data format | |
| let compressed_mint_instruction_data = MintInstructionData::try_from(compressed_mint) | |
| .map_err(|e| { | |
| RpcError::CustomError(format!("Failed to convert compressed mint: {:?}", e)) | |
| })?; |
🤖 Prompt for AI Agents
In `@sdk-libs/token-client/src/instructions/update_compressed_mint.rs` around
lines 71 - 80, The code unnecessarily clones compressed_mint before calling
MintInstructionData::try_from; change the call to consume the owned
compressed_mint (pass compressed_mint directly to MintInstructionData::try_from)
instead of compressed_mint.clone(), ensuring no further use of compressed_mint
after that point (or update subsequent code to use the resulting
MintInstructionData); locate this in the block where BorshDeserialize produces
compressed_mint and replace the clone usage so the value is moved into
MintInstructionData::try_from.
| pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> { | ||
| let source_is_light_token = is_token_account(&self.source_account) | ||
| .map_err(|_| ProgramError::Custom(TokenSdkError::CannotDetermineAccountType.into()))?; | ||
| let dest_is_light_token = is_token_account(&self.destination_account) | ||
| .map_err(|_| ProgramError::Custom(TokenSdkError::CannotDetermineAccountType.into()))?; | ||
|
|
||
| match (source_is_light_token, dest_is_light_token) { | ||
| (true, true) => TransferCpi { | ||
| source: self.source_account.clone(), | ||
| destination: self.destination_account.clone(), | ||
| amount: self.amount, | ||
| authority: self.authority.clone(), | ||
| max_top_up: None, // No limit by default | ||
| use solana_cpi::invoke_signed; | ||
|
|
||
| let transfer_type = | ||
| determine_transfer_type(self.source_account.owner, self.destination_account.owner)?; | ||
| let instruction = self.instruction()?; | ||
|
|
||
| match transfer_type { | ||
| TransferType::LightToLight => { | ||
| let account_infos = [ | ||
| self.source_account, | ||
| self.destination_account, | ||
| self.authority, | ||
| ]; | ||
| invoke_signed(&instruction, &account_infos, signer_seeds) | ||
| } | ||
| .invoke_signed(signer_seeds), | ||
|
|
||
| (true, false) => { | ||
| TransferType::LightToSpl => { | ||
| let config = self.spl_interface.ok_or_else(|| { | ||
| ProgramError::Custom(TokenSdkError::SplInterfaceRequired.into()) | ||
| })?; | ||
|
|
||
| TransferToSplCpi { | ||
| source: self.source_account.clone(), | ||
| destination_spl_token_account: self.destination_account.clone(), | ||
| amount: self.amount, | ||
| authority: self.authority.clone(), | ||
| mint: config.mint.clone(), | ||
| payer: self.payer.clone(), | ||
| spl_interface_pda: config.spl_interface_pda.clone(), | ||
| spl_interface_pda_bump: config.spl_interface_pda_bump, | ||
| decimals: self.decimals, | ||
| spl_token_program: config.spl_token_program.clone(), | ||
| compressed_token_program_authority: self | ||
| .compressed_token_program_authority | ||
| .clone(), | ||
| } | ||
| .invoke_signed(signer_seeds) | ||
| let account_infos = [ | ||
| self.compressed_token_program_authority, | ||
| self.payer, | ||
| config.mint, | ||
| self.source_account, | ||
| self.destination_account, | ||
| self.authority, | ||
| config.spl_interface_pda, | ||
| config.spl_token_program, | ||
| ]; | ||
| invoke_signed(&instruction, &account_infos, signer_seeds) | ||
| } | ||
|
|
||
| (false, true) => { | ||
| TransferType::SplToLight => { | ||
| let config = self.spl_interface.ok_or_else(|| { | ||
| ProgramError::Custom(TokenSdkError::SplInterfaceRequired.into()) | ||
| })?; | ||
|
|
||
| TransferFromSplCpi { | ||
| source_spl_token_account: self.source_account.clone(), | ||
| destination: self.destination_account.clone(), | ||
| amount: self.amount, | ||
| authority: self.authority.clone(), | ||
| mint: config.mint.clone(), | ||
| payer: self.payer.clone(), | ||
| spl_interface_pda: config.spl_interface_pda.clone(), | ||
| spl_interface_pda_bump: config.spl_interface_pda_bump, | ||
| decimals: self.decimals, | ||
| spl_token_program: config.spl_token_program.clone(), | ||
| compressed_token_program_authority: self | ||
| .compressed_token_program_authority | ||
| .clone(), | ||
| system_program: self.system_program.clone(), | ||
| } | ||
| .invoke_signed(signer_seeds) | ||
| let account_infos = [ | ||
| self.compressed_token_program_authority, | ||
| self.payer, | ||
| config.mint, | ||
| self.destination_account, | ||
| self.authority, | ||
| self.source_account, | ||
| config.spl_interface_pda, | ||
| config.spl_token_program, | ||
| self.system_program, | ||
| ]; | ||
| invoke_signed(&instruction, &account_infos, signer_seeds) | ||
| } | ||
|
|
||
| (false, false) => Err(ProgramError::Custom( | ||
| TokenSdkError::UseRegularSplTransfer.into(), | ||
| )), | ||
| TransferType::SplToSpl => { | ||
| let config = self.spl_interface.ok_or_else(|| { | ||
| ProgramError::Custom(TokenSdkError::SplInterfaceRequired.into()) | ||
| })?; | ||
| let account_infos = [ | ||
| self.source_account, | ||
| config.mint, | ||
| self.destination_account, | ||
| self.authority, | ||
| ]; | ||
| invoke_signed(&instruction, &account_infos, signer_seeds) | ||
| } | ||
| } |
There was a problem hiding this comment.
invoke_signed() has the same double-call pattern.
Same issue as invoke() - determine_transfer_type is called twice (lines 407-408 and implicitly in line 409).
🤖 Prompt for AI Agents
In `@sdk-libs/token-sdk/src/token/transfer_interface.rs` around lines 404 - 468,
The code calls determine_transfer_type twice (once explicitly and again
indirectly when building the instruction), so change invoke_signed to compute
transfer_type once and reuse it when building the instruction: call
determine_transfer_type(self.source_account.owner,
self.destination_account.owner) and store the result in transfer_type, then
generate the instruction using a new or modified method that accepts the
already-determined TransferType (e.g., add an instruction_for(&self,
transfer_type: TransferType) or change instruction(&self) to accept
transfer_type) and use transfer_type in the match arms
(TransferType::LightToLight, LightToSpl, SplToLight, SplToSpl) to avoid the
duplicate call.
Changes
Type Renames:
Error Renames:
4. InvalidCMintOwner -> InvalidMintOwner
5. CMintNotInitialized -> MintNotInitialized
6. CMintBorrowFailed -> MintBorrowFailed
7. CMintDeserializationFailed -> MintDeserializationFailed
File Renames:
8. compress_and_close_cmint.rs -> compress_and_close_mint.rs
9. create_cmint.rs -> create_mint.rs
10. decompress_cmint.rs -> decompress_mint.rs
Bug Fix:
11. create_compressed_mint_instruction now uses MintAction with empty actions instead of CreateMint builder (which always added DecompressMint)
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.