refactor: ctoken sdk builder instructions2#2069
Conversation
refactor: transfer ctoken stash refactor: compressed-token-sdk move create token account stash stash feat: ctoken create cmint fixed compilation issues feat: add mint to ctoken stash ctoken test test_mint_to_ctoken works test: sdk transfer spl ctokens test transfer interface refactor: split up transfer interface rs
WalkthroughLarge SDK refactor: replaced many free-function instruction builders with struct-based builders and account-info wrappers, centralized mint-action account-meta generation into MintActionMetaConfig instance API, added new ctoken/ATA/CMint/mint-to/transfer modules, reorganized exports, and applied minor program-side predicate/formatting tweaks. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant SDK
participant MetaCfg as MintActionMetaConfig
participant Program as Solana
rect rgb(240,250,240)
Note over Client,SDK: Builder -> MetaCfg -> Instruction flow
Client->>SDK: Build (e.g., CreateCMint::new(params,...))
SDK->>MetaCfg: MintActionMetaConfig::new(_payer_, authority, ...)
alt has MintToCompressed
SDK->>MetaCfg: .with_mint_compressed_tokens()
end
SDK->>MetaCfg: config.to_account_metas()
MetaCfg->>SDK: Vec<AccountMeta>
SDK->>Program: assemble Instruction(data + metas)
SDK->>Program: invoke / invoke_signed
Program-->>SDK: result
end
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120+ minutes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ 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 |
| "sdk-tests/sdk-v1-native-test", | ||
| "sdk-tests/sdk-token-test", | ||
| "sdk-tests/sdk-compressible-test", | ||
| "sdk-tests/sdk-ctoken-test", |
3eaa52a to
574888f
Compare
There was a problem hiding this comment.
Actionable comments posted: 11
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
sdk-libs/token-client/src/instructions/create_mint.rs (1)
43-88: Fix error handling for validity proof results to prevent panics on empty responsesThe code currently uses direct indexing and unwrap on RPC results, which will panic if the indexer returns empty collections or missing proofs. Per codebase patterns (e.g.,
register_forester.rs,compress_and_close_forester.rs), return structured errors instead:let proof = rpc_result .proof .0 .ok_or_else(|| RpcError::CustomError("missing validity proof".to_string()))?; let first_address = rpc_result .addresses .get(0) .ok_or_else(|| RpcError::CustomError("no addresses returned for compressed mint".to_string()))?; let address_merkle_tree_root_index = first_address.root_index;Additionally,
version: 3(line 65) hardcodes protocol knowledge in the client. The on-chain validator checks this value, but if the protocol evolves, consider externalizing this as a constant to avoid silent drift.sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_to_compressed/instruction.rs (1)
43-57: Required parametersoutput_queue_tokens,decompressed_mint_config, andtoken_poolare silently dropped—either remove them from the API or plumb them throughThe refactoring centralizes account metas via
MintActionMetaConfig, but creates a mismatch between what the function signature accepts and what it actually uses:
output_queue_tokensis a requiredPubkey, yet it's destructured as_and the function instead usesoutput_queue_cmintinternally viawith_mint_compressed_tokens().decompressed_mint_configandtoken_poolboth carry doc comments stating "Required if the mint is decompressed," yet they too are ignored at lines 52 and 56.- A
new_decompressed()method exists inMintToCompressedMetaConfigbut is never called, so the decompressed path is effectively unavailable.If a caller attempts to mint to a decompressed account and passes these values, they will be silently lost, causing the program instruction to lack the required accounts. Either remove these fields from
MintToCompressedInputsto clarify the API, or plumb them through by detecting the decompressed case and calling the appropriateMintActionMetaConfigconstructor (e.g.,new_decompressed()whendecompressed_mint_config.is_some()).Also applies to: 75-94
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (60)
Cargo.lockis excluded by!**/*.lockand included by noneCargo.tomlis excluded by none and included by noneprogram-tests/compressed-token-test/tests/ctoken/compress_and_close.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/ctoken/create.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/ctoken/create_ata.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/ctoken/create_ata2.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/ctoken/functional.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/ctoken/functional_ata.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/ctoken/shared.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/mint/cpi_context.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/mint/edge_cases.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/mint/failing.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/mint/functional.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/mint/random.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/transfer2/compress_failing.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/transfer2/compress_spl_failing.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/transfer2/decompress_failing.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/transfer2/no_system_program_cpi_failing.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/transfer2/shared.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/transfer2/spl_ctoken.rsis excluded by none and included by noneprogram-tests/registry-test/tests/compressible.rsis excluded by none and included by noneprogram-tests/utils/src/assert_create_token_account.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/src/instruction_accounts.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/src/instructions/create_user_record_and_game_session.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/src/instructions/decompress_accounts_idempotent.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/tests/game_session_tests.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/tests/helpers.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/tests/idempotency_tests.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/tests/multi_account_tests.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/Cargo.lockis excluded by!**/*.lockand included by nonesdk-tests/sdk-ctoken-test/Cargo.tomlis excluded by none and included by nonesdk-tests/sdk-ctoken-test/README.mdis excluded by none and included by nonesdk-tests/sdk-ctoken-test/Xargo.tomlis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/close.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/create_ata.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/create_ata2.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/create_cmint.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/create_token_account.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/lib.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/mint_to_ctoken.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/transfer.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/transfer_interface.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/transfer_spl_ctoken.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/shared.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_close.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_create_ata.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_create_ata_v2.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_create_cmint.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_create_token_account.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_mint_to_ctoken.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_transfer.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_transfer_interface.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_transfer_spl_ctoken.rsis excluded by none and included by nonesdk-tests/sdk-token-test/src/process_compress_full_and_close.rsis excluded by none and included by nonesdk-tests/sdk-token-test/src/process_create_ctoken_with_compress_to_pubkey.rsis excluded by none and included by nonesdk-tests/sdk-token-test/tests/compress_and_close_cpi.rsis excluded by none and included by nonesdk-tests/sdk-token-test/tests/decompress_full_cpi.rsis excluded by none and included by nonesdk-tests/sdk-token-test/tests/pda_ctoken.rsis excluded by none and included by nonesdk-tests/sdk-token-test/tests/test_4_transfer2.rsis excluded by none and included by nonesdk-tests/sdk-token-test/tests/test_compress_full_and_close.rsis excluded by none and included by none
📒 Files selected for processing (31)
program-libs/compressed-account/src/instruction_data/traits.rs(1 hunks)programs/compressed-token/program/src/mint_action/accounts.rs(1 hunks)programs/compressed-token/program/src/mint_action/processor.rs(0 hunks)sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs(1 hunks)sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs(3 hunks)sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/mod.rs(1 hunks)sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_to_compressed/instruction.rs(3 hunks)sdk-libs/compressed-token-sdk/src/compressed_token/v2/update_compressed_mint/instruction.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/close.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/compressible.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/create.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/create_associated_token_account.rs(0 hunks)sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/instruction.rs(0 hunks)sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/mod.rs(0 hunks)sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/mod.rs(2 hunks)sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken.rs(0 hunks)sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken_spl.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs(4 hunks)sdk-libs/compressed-token-sdk/src/ctoken/transfer_spl_ctoken.rs(1 hunks)sdk-libs/compressed-token-sdk/src/error.rs(1 hunks)sdk-libs/compressed-token-sdk/src/lib.rs(1 hunks)sdk-libs/compressed-token-sdk/tests/create_associated_token_account.rs(3 hunks)sdk-libs/token-client/src/actions/create_compressible_token_account.rs(2 hunks)sdk-libs/token-client/src/actions/mint_action.rs(1 hunks)sdk-libs/token-client/src/actions/transfer2/ctoken_to_spl.rs(1 hunks)sdk-libs/token-client/src/actions/transfer2/spl_to_ctoken.rs(3 hunks)sdk-libs/token-client/src/instructions/create_mint.rs(2 hunks)sdk-libs/token-client/src/instructions/mint_action.rs(3 hunks)
💤 Files with no reviewable changes (5)
- sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken.rs
- sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/mod.rs
- sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/instruction.rs
- programs/compressed-token/program/src/mint_action/processor.rs
- sdk-libs/compressed-token-sdk/src/ctoken/create_associated_token_account.rs
🧰 Additional context used
🧬 Code graph analysis (20)
sdk-libs/token-client/src/actions/mint_action.rs (1)
sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (1)
derive_ctoken_ata(20-29)
sdk-libs/token-client/src/actions/transfer2/ctoken_to_spl.rs (1)
sdk-libs/compressed-token-sdk/src/token_pool.rs (1)
find_token_pool_pda_with_index(20-28)
sdk-libs/token-client/src/instructions/create_mint.rs (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs (2)
derive_compressed_mint_address(193-202)find_spl_mint_address(212-217)
sdk-libs/token-client/src/actions/transfer2/spl_to_ctoken.rs (1)
sdk-libs/compressed-token-sdk/src/token_pool.rs (1)
find_token_pool_pda_with_index(20-28)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
new_create_mint(22-40)
sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (3)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (3)
get_mint_action_instruction_account_metas_cpi_write(181-209)new_cpi_context(64-85)new_create_mint(22-40)program-libs/compressed-account/src/instruction_data/traits.rs (6)
cpi_context(58-58)data(26-34)data(87-87)data(108-108)address(84-84)address(105-105)program-libs/ctoken-types/src/instructions/mint_action/builder.rs (2)
new_mint(44-63)new_mint_write_to_cpi_context(65-84)
sdk-libs/compressed-token-sdk/src/ctoken/compressible.rs (2)
sdk-libs/compressed-token-sdk/src/ctoken/create.rs (2)
new(24-38)new(102-116)sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (3)
new(47-63)new(155-174)new(268-284)
sdk-libs/compressed-token-sdk/tests/create_associated_token_account.rs (1)
sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (1)
derive_ctoken_ata(20-29)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (1)
sdk-libs/compressed-token-sdk/src/utils.rs (1)
is_ctoken_account(22-37)
sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (2)
sdk-libs/compressed-token-sdk/src/ctoken/create.rs (6)
invoke(122-138)from(160-178)new(24-38)new(102-116)instruction(40-90)instruction(118-120)sdk-libs/compressed-token-sdk/src/ctoken/compressible.rs (2)
new(33-39)new(57-73)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_spl_ctoken.rs (4)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken_spl.rs (5)
invoke(47-61)invoke_signed(63-77)instruction(43-45)instruction(98-158)from(81-93)sdk-libs/compressed-token-sdk/src/compressed_token/v2/transfer2/instruction.rs (1)
create_transfer2_instruction(69-138)sdk-libs/compressed-token-sdk/src/compressed_token/v2/account2.rs (2)
compress_spl(193-220)decompress_ctoken(224-247)sdk-libs/compressed-token-sdk/src/compressed_token/v2/transfer2/account_metas.rs (1)
new_decompressed_accounts_only(33-46)
sdk-libs/token-client/src/instructions/mint_action.rs (2)
sdk-libs/token-client/src/actions/mint_action.rs (1)
mint_action(24-59)sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
new(43-61)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken_spl.rs (4)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_spl_ctoken.rs (5)
invoke(48-62)invoke_signed(64-78)instruction(44-46)instruction(98-152)from(82-94)sdk-libs/compressed-token-sdk/src/compressed_token/v2/transfer2/instruction.rs (1)
create_transfer2_instruction(69-138)sdk-libs/compressed-token-sdk/src/compressed_token/v2/account2.rs (2)
compress_ctoken(169-190)decompress_spl(250-279)sdk-libs/compressed-token-sdk/src/compressed_token/v2/transfer2/account_metas.rs (1)
new_decompressed_accounts_only(33-46)
sdk-libs/compressed-token-sdk/src/ctoken/close.rs (1)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken.rs (5)
invoke(27-31)invoke_signed(33-37)instruction(23-25)instruction(52-66)from(41-48)
sdk-libs/compressed-token-sdk/src/ctoken/create.rs (2)
sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (11)
invoke(185-204)invoke(380-403)new(47-63)new(155-174)new(268-284)instruction(89-140)instruction(181-183)instruction(310-361)instruction(376-378)from(229-249)from(432-452)sdk-libs/compressed-token-sdk/src/ctoken/compressible.rs (2)
new(33-39)new(57-73)
sdk-libs/compressed-token-sdk/src/ctoken/mod.rs (1)
sdk-libs/sdk/src/compressible/close.rs (1)
close(6-40)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_to_compressed/instruction.rs (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
new(43-61)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
sdk-libs/token-client/src/actions/mint_action.rs (1)
mint_action(24-59)
sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs (3)
sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (12)
invoke(327-350)invoke_signed(352-375)invoke_signed(421-425)new(66-82)new(170-189)new(215-227)with_cpi_context(84-88)instruction(90-149)instruction(229-280)instruction(323-325)instruction(417-419)from(429-436)sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (2)
get_mint_action_instruction_account_metas_cpi_write(181-209)new_cpi_context(64-85)programs/compressed-token/program/src/mint_action/accounts.rs (1)
new(379-469)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/mod.rs (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
get_mint_action_instruction_account_metas_cpi_write(181-209)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Test batched-merkle-tree-simulate
- GitHub Check: programs (account-compression-and-registry, ["cargo-test-sbf -p account-compression-test", "cargo...
- GitHub Check: programs (compressed-token-batched-tree, ["cargo-test-sbf -p compressed-token-test -- test_transf...
🔇 Additional comments (20)
program-libs/compressed-account/src/instruction_data/traits.rs (1)
26-34: Good formatting for clarity between logical sections.The blank line inserted after the discriminator (line 31) improves readability by visually separating the "add discriminator" step from the "add serialized data" step. No logic or behavioral changes; the trait's public interface and semantics remain intact.
sdk-libs/compressed-token-sdk/src/error.rs (2)
114-114: Verification complete: Error code renumbering is safe internally.The codebase has no hardcoded references to 17026 or 17024. Error code mapping is centralized in a single
From<TokenSdkError>implementation (lines 89–116), and tests use parametric error code comparison rather than hardcoded values. The renumbering creates a contiguous sequence (17001–17024) with no gaps—standard practice when removing error variants.The original concern about downstream code matching hardcoded error numbers is valid for external consumers, but this codebase shows no such risk. If your error codes are part of a public API contract, consider documenting the change or reserving the gaps for backward compatibility in future releases.
13-74: I'll verify a few more angles to be thorough—let me check if tests or builder code reference these variants, and confirm the compile-time validation moved where expected.Let me search for the builder code and test references to confirm the constraints moved to compile-time validation:
This is a breaking API change that's safely isolated within the codebase—verify it's intentional and documented for external consumers.
The verification confirms:
- No references to
CreateMintDataRequiredorCreateMintMustBeNoneexist in the codebase- Removing publicly exposed items causes downstream code to fail to compile and is a major semver change
- The refactoring is sound (builders using the typestate pattern enforce constraints at compile-time rather than runtime)
This is a deliberate breaking change aligned with moving from runtime error handling to compile-time validation. Ensure this is:
- Reflected in a major version bump per semver
- Documented in changelog/migration guide for external SDK consumers
- Tested to confirm no edge cases exist in related error handling code
sdk-libs/compressed-token-sdk/src/lib.rs (1)
14-14: TheCompressedProofre-export is correctly justified and intentional.Verification confirms that
CompressedProofis actively used in the public API as a field in theCreateCMintParamsstruct (line 31 ofsrc/ctoken/create_cmint.rs). Since this struct is public and exported throughpub mod ctoken, consumers need direct access to theCompressedProoftype—making the re-export at the crate root essential for usability. This is consistent with the params-struct builder pattern introduced in this refactor.The code change is solid. If you want to further enhance clarity, consider adding a one-line doc comment to this re-export explaining its relationship to the builder API, though this is optional.
programs/compressed-token/program/src/mint_action/accounts.rs (1)
452-458: Aligninghas_mint_to_actionswith actual queue usage looks correctRestricting
has_mint_to_actionstoMintToCompressedhere matches howtokens_out_queueis used (only new compressed outputs require that queue) and brings the non‑CPI path in line with the CPI path logic above. I don’t see other usages ofhas_mint_to_actionsin this file that would still needMintToCToken, so this tightening looks safe and more accurate.sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (3)
4-77: TransferInterface SPL bridge wiring and routing look soundThe Split of the SPL-bridge metadata into
SplBridgeConfigand theTransferInterface::with_spl_bridgebuilder reads clean, and the routing based onis_ctoken_accountfor the three supported cases (ctoken↔ctoken, ctoken→SPL, SPL→ctoken) is consistent. TheIncompleteSplBridgeConfigerror on missing bridge config is an appropriate guardrail.
155-176: Field rename todestination_ctoken_accountis consistent with the SPL→ctoken helpersUsing
destination_ctoken_accounthere matches theTransferSplToCtokenAccountInfosstruct intransfer_spl_ctoken.rsand keeps the SPL→ctoken path aligned between regular and signed invokes. No issues spotted with the account mapping.
224-244: Signed SPL→ctoken path mirrors the unsigned variant correctlyThe
invoke_signedbranch mirrors the unsigned case, including thedestination_ctoken_accountmapping andIncompleteSplBridgeConfigguard, so the signer‑seed variant should behave identically aside from the additional signing power.sdk-libs/compressed-token-sdk/src/ctoken/compressible.rs (1)
1-79: Compressible params builders are consistent with the create flowsThe
CompressibleParamsandCompressibleParamsInfosdefaults andnew/with_compress_to_pubkeybuilders line up with how they’re consumed increate.rsandcreate_ata.rs(rent_payment, top‑up, version, and optional compress‑to pubkey). The shapes look correct and future‑proof for passing through additional compressible config as needed.sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken_spl.rs (3)
17-40: CToken→SPL account-info structs match the intended bridge surfaceThe
TransferCtokenToSplandTransferCtokenToSplAccountInfosshapes capture exactly the accounts needed for the two‑step bridge (ctoken source, SPL dest, pool, mint, payer, program authority, SPL token program), and the conversionFrom<&…>is a straightforward key/amount copy. No structural issues here.
47-77: CPI invoke helpers are consistent with the meta layoutThe
invoke/invoke_signedhelpers respect the “cpi_authority PDA, fee_payer, packed accounts…” ordering used elsewhere (e.g., SPL→ctoken), so the account slice should line up with the metas produced byTransferCtokenToSpl::instruction. This keeps the CPI surface predictable.
96-158: Index wiring for compress/decompress steps looks correctThe two
CTokenAccount2entries use indices that match the packed metas:
compress_ctoken(self.amount, 0, 1, 3)→ mint at 0, source ctoken at 1, authority at 3.decompress_spl(self.amount, 0, 2, 4, 0, self.token_pool_pda_bump)→ mint at 0, destination SPL at 2, pool PDA at 4, pool index 0, bump fromtoken_pool_pda_bump.Given the packed accounts
[mint, source_ctoken, dest_spl, authority, pool_pda, spl_program], this wiring matches the transfer2 conventions and mirrors the existing SPL→ctoken implementation.sdk-libs/compressed-token-sdk/src/ctoken/create.rs (2)
14-90: CreateCTokenAccount builder and account metas look consistent with the ATA pathThe instruction builder correctly:
- Encodes the optional compressible extension (version, rent epochs, top‑up presence, optional compress‑to pubkey).
- Prepends the expected InitializeAccount3 discriminator byte.
- Builds two account layouts:
- Compressible:
[account, mint, payer, compressible_config, system_program, rent_sponsor].- Non‑compressible:
[account, mint].This matches the patterns used in
create_ata.rsfor compressible vs non‑compressible initialization, including the convention of passing the realsystem_programaccount via infos while using a placeholder key in the metas.
159-178: Infos→builder conversion preserves compressible settings correctlyThe
From<&CreateCTokenAccountInfos<'info>> for CreateCTokenAccountimplementation faithfully maps:
- Payer/account/mint/owner pubkeys, and
- All compressible parameters (config pubkey, rent_sponsor, epochs, lamports_per_write, optional compress_to_account_pubkey, token_account_version).
Dropping
system_programfrom the params is intentional and keepsCompressibleParamsfocused on config rather than CPI plumbing.sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (1)
15-29: PDA derivation and discriminators follow existing compressed-token patternsThe
derive_ctoken_ataseeds and program id usage match the rest of the compressed-token SDK conventions, and the discriminator constants are clearly separated for V1/V2 and idempotent variants. I don’t see any functional issues here assuming these values match the on-chain program spec.sdk-libs/token-client/src/actions/mint_action.rs (1)
101-112: Importingctoken::derive_ctoken_ataaligns with the new API surfaceSwitching to
light_compressed_token_sdk::ctoken::derive_ctoken_atakeeps the mint-to-ctoken ATA derivation logic intact while reflecting the new consolidated ctokens module layout. The usage inmint_action_comprehensivelooks correct.sdk-libs/token-client/src/actions/transfer2/ctoken_to_spl.rs (1)
5-7: UpdatedTransferCtokenToSplimport matches the new ctokens module layoutThe move from
ctoken::transfer_interface::TransferCtokenToSpltoctoken::TransferCtokenToSplis consistent with the refactor and keeps the transfer construction unchanged.sdk-libs/token-client/src/actions/transfer2/spl_to_ctoken.rs (1)
5-7: Renaming todestination_ctoken_accountimproves clarity with no behavioral changeUsing
TransferSplToCtokenfrom thectokenroot and renaming the parameter/field fromtotodestination_ctoken_accountmakes the direction of value flow much clearer. The struct construction matches the new field name, so everything stays consistent.Also applies to: 19-20, 36-41
sdk-libs/token-client/src/actions/create_compressible_token_account.rs (1)
57-74: Good refactor toCompressibleParams+CreateCTokenAccountbuilder; just verify param semanticsThe move to
CompressibleParamsandCreateCTokenAccount::new(...).instruction()keeps all the previous inputs flowing through (config PDA, rent sponsor, prepaid epochs, optionallamports_per_write, andtoken_account_version), which makes the behavior easier to reason about.Two minor points to double-check:
- Confirm that
pre_pay_num_epochs: num_prepaid_epochsandlamports_per_writeline up with the on-chain struct definition (no widening/narrowing issues or changed units).- If the SDK offers a
CompressibleParams::new/default_for_versionhelper, using that instead of an open struct literal would reduce the chance of missing fields when the struct evolves.Otherwise the wiring here looks solid.
sdk-libs/compressed-token-sdk/tests/create_associated_token_account.rs (1)
1-27: Solid coverage of the new ATA builder + compressible paramsThese test updates look good: they exercise
- Discriminator selection for regular vs idempotent forms.
- Data and account-list consistency between the two paths.
new_with_bumpvariants for both non-idempotent and idempotent.- The expected account count when
CompressibleParams::default()is used.That’s a nice safety net for the new
CreateAssociatedTokenAccountbuilder surface and should catch regressions in discriminator wiring or account metas.Also applies to: 34-47, 57-87, 89-102
| let meta_config = if cpi_context_pubkey.is_some() { | ||
| MintActionMetaConfig::new_cpi_context( | ||
| &instruction_data, | ||
| input.mint_authority, | ||
| input.payer, | ||
| input.mint_authority, | ||
| cpi_context_pubkey.unwrap(), | ||
| )? | ||
| } else { | ||
| MintActionMetaConfig::new_create_mint( | ||
| &instruction_data, | ||
| input.payer, | ||
| input.mint_authority, | ||
| input.mint_signer, | ||
| input.payer, | ||
| input.address_tree_pubkey, | ||
| input.output_queue, | ||
| )? | ||
| ) | ||
| }; | ||
|
|
||
| let account_metas = | ||
| get_mint_action_instruction_account_metas(meta_config, &compressed_mint_with_context); | ||
| let account_metas = meta_config.to_account_metas(); | ||
|
|
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Meta-config branch looks correct; consider simplifying Option handling
The switch to MintActionMetaConfig::new_cpi_context / new_create_mint plus to_account_metas() keeps behavior centralized, which is a good refactor.
You can make this a bit cleaner (and avoid is_some + unwrap) by matching the Option directly:
- let meta_config = if cpi_context_pubkey.is_some() {
- MintActionMetaConfig::new_cpi_context(
- &instruction_data,
- input.payer,
- input.mint_authority,
- cpi_context_pubkey.unwrap(),
- )?
- } else {
- MintActionMetaConfig::new_create_mint(
- input.payer,
- input.mint_authority,
- input.mint_signer,
- input.address_tree_pubkey,
- input.output_queue,
- )
- };
+ let meta_config = if let Some(cpi_pubkey) = cpi_context_pubkey {
+ MintActionMetaConfig::new_cpi_context(
+ &instruction_data,
+ input.payer,
+ input.mint_authority,
+ cpi_pubkey,
+ )?
+ } else {
+ MintActionMetaConfig::new_create_mint(
+ input.payer,
+ input.mint_authority,
+ input.mint_signer,
+ input.address_tree_pubkey,
+ input.output_queue,
+ )
+ };🤖 Prompt for AI Agents
In
sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs
around lines 83 to 101, the current code uses cpi_context_pubkey.is_some()
combined with cpi_context_pubkey.unwrap(), which is unnecessary and brittle;
replace that pattern by matching the Option directly (e.g., use match or if let
Some(pubkey) = cpi_context_pubkey { ... } else { ... }) to call
MintActionMetaConfig::new_cpi_context(pubkey, ...) in the Some branch and
MintActionMetaConfig::new_create_mint(...) in the None branch, preserving the
existing error propagation (?) and then call meta_config.to_account_metas() as
before.
| metas.push(AccountMeta::new(self.output_queue, false)); | ||
|
|
||
| metas.push(AccountMeta::new(config.tree_pubkey, false)); | ||
| metas.push(AccountMeta::new(self.tree_pubkey, false)); | ||
|
|
||
| if !config.create_mint { | ||
| if let Some(input_queue) = config.input_queue { | ||
| metas.push(AccountMeta::new(input_queue, false)); | ||
| // input_queue is present when NOT creating a new mint (mint_signer.is_none()) | ||
| if self.mint_signer.is_none() { | ||
| if let Some(input_queue) = self.input_queue { | ||
| metas.push(AccountMeta::new(input_queue, false)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if config.has_mint_to_actions { | ||
| let tokens_out_queue = config.tokens_out_queue.unwrap_or(config.output_queue); | ||
| metas.push(AccountMeta::new(tokens_out_queue, false)); | ||
| } | ||
| // tokens_out_queue is present when there are MintToCompressed actions | ||
| if let Some(tokens_out_queue) = self.tokens_out_queue { | ||
| metas.push(AccountMeta::new(tokens_out_queue, false)); | ||
| } |
There was a problem hiding this comment.
Skip queue/tree metas when cpi_context is present
MintActionMetaConfig::new_cpi_context deliberately fills tree_pubkey and output_queue with Pubkey::default(). Because to_account_metas still pushes those slots (and the derived input_queue / tokens_out_queue) we hand back instructions that require the system program in those positions. The CPI helpers (for example MintToCTokenInfos::invoke) then feed the real queue/tree accounts and the runtime throws InstructionError::AccountMismatch immediately. Gate the queue-related metas behind the non-CPI path so CPI callers no longer desync the account list.
Apply this diff to keep queue-related metas out of the CPI-context case:
- metas.push(AccountMeta::new(self.output_queue, false));
-
- metas.push(AccountMeta::new(self.tree_pubkey, false));
-
- // input_queue is present when NOT creating a new mint (mint_signer.is_none())
- if self.mint_signer.is_none() {
- if let Some(input_queue) = self.input_queue {
- metas.push(AccountMeta::new(input_queue, false));
- }
- }
-
- // tokens_out_queue is present when there are MintToCompressed actions
- if let Some(tokens_out_queue) = self.tokens_out_queue {
- metas.push(AccountMeta::new(tokens_out_queue, false));
- }
+ if self.cpi_context.is_none() {
+ metas.push(AccountMeta::new(self.output_queue, false));
+ metas.push(AccountMeta::new(self.tree_pubkey, false));
+
+ // input_queue is present when NOT creating a new mint (mint_signer.is_none())
+ if self.mint_signer.is_none() {
+ if let Some(input_queue) = self.input_queue {
+ metas.push(AccountMeta::new(input_queue, false));
+ }
+ }
+
+ // tokens_out_queue is present when there are MintToCompressed actions
+ if let Some(tokens_out_queue) = self.tokens_out_queue {
+ metas.push(AccountMeta::new(tokens_out_queue, false));
+ }
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| metas.push(AccountMeta::new(self.output_queue, false)); | |
| metas.push(AccountMeta::new(config.tree_pubkey, false)); | |
| metas.push(AccountMeta::new(self.tree_pubkey, false)); | |
| if !config.create_mint { | |
| if let Some(input_queue) = config.input_queue { | |
| metas.push(AccountMeta::new(input_queue, false)); | |
| // input_queue is present when NOT creating a new mint (mint_signer.is_none()) | |
| if self.mint_signer.is_none() { | |
| if let Some(input_queue) = self.input_queue { | |
| metas.push(AccountMeta::new(input_queue, false)); | |
| } | |
| } | |
| } | |
| if config.has_mint_to_actions { | |
| let tokens_out_queue = config.tokens_out_queue.unwrap_or(config.output_queue); | |
| metas.push(AccountMeta::new(tokens_out_queue, false)); | |
| } | |
| // tokens_out_queue is present when there are MintToCompressed actions | |
| if let Some(tokens_out_queue) = self.tokens_out_queue { | |
| metas.push(AccountMeta::new(tokens_out_queue, false)); | |
| } | |
| if self.cpi_context.is_none() { | |
| metas.push(AccountMeta::new(self.output_queue, false)); | |
| metas.push(AccountMeta::new(self.tree_pubkey, false)); | |
| // input_queue is present when NOT creating a new mint (mint_signer.is_none()) | |
| if self.mint_signer.is_none() { | |
| if let Some(input_queue) = self.input_queue { | |
| metas.push(AccountMeta::new(input_queue, false)); | |
| } | |
| } | |
| // tokens_out_queue is present when there are MintToCompressed actions | |
| if let Some(tokens_out_queue) = self.tokens_out_queue { | |
| metas.push(AccountMeta::new(tokens_out_queue, false)); | |
| } | |
| } |
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/mod.rs
Show resolved
Hide resolved
| pub struct CreateCTokenAccountInfos<'info> { | ||
| pub payer: AccountInfo<'info>, | ||
| pub account: AccountInfo<'info>, | ||
| pub mint: AccountInfo<'info>, | ||
| pub owner: Pubkey, | ||
| pub compressible: Option<CompressibleParamsInfos<'info>>, | ||
| } | ||
|
|
||
| impl<'info> CreateCTokenAccountInfos<'info> { | ||
| pub fn new( | ||
| payer: AccountInfo<'info>, | ||
| account: AccountInfo<'info>, | ||
| mint: AccountInfo<'info>, | ||
| owner: Pubkey, | ||
| compressible: CompressibleParamsInfos<'info>, | ||
| ) -> Self { | ||
| Self { | ||
| payer, | ||
| account, | ||
| mint, | ||
| owner, | ||
| compressible: Some(compressible), | ||
| } | ||
| } | ||
|
|
||
| pub fn instruction(&self) -> Result<Instruction, ProgramError> { | ||
| CreateCTokenAccount::from(self).instruction() | ||
| } | ||
|
|
||
| pub fn invoke(self) -> Result<(), ProgramError> { | ||
| let instruction = self.instruction()?; | ||
| if let Some(compressible) = self.compressible { | ||
| let account_infos = [ | ||
| self.account, | ||
| self.mint, | ||
| self.payer, | ||
| compressible.compressible_config, | ||
| compressible.system_program, | ||
| compressible.rent_sponsor, | ||
| ]; | ||
| invoke(&instruction, &account_infos) | ||
| } else { | ||
| let account_infos = [self.account, self.mint]; | ||
| invoke(&instruction, &account_infos) | ||
| } | ||
| } | ||
|
|
||
| pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> { | ||
| let instruction = self.instruction()?; | ||
| if let Some(compressible) = self.compressible { | ||
| let account_infos = [ | ||
| self.account, | ||
| self.mint, | ||
| self.payer, | ||
| compressible.compressible_config, | ||
| compressible.system_program, | ||
| compressible.rent_sponsor, | ||
| ]; | ||
| invoke_signed(&instruction, &account_infos, signer_seeds) | ||
| } else { | ||
| let account_infos = [self.account, self.mint]; | ||
| invoke_signed(&instruction, &account_infos, signer_seeds) | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Double‑check signer semantics for the non‑compressible create path
In the compressible path, the account meta is created with AccountMeta::new(self.account, true), but in the non‑compressible path it’s AccountMeta::new(self.account, false). For InitializeAccount3‑style flows it’s common for the account being initialized to be a signer regardless of whether a compressible extension is present.
If the underlying ctoken program enforces account.is_signer for non‑compressible initializes as well, this asymmetry could either cause failures or weaken the check. Please confirm the program’s expectation and, if it should always be a signer, change the non‑compressible branch to:
- vec![
- AccountMeta::new(self.account, false),
- AccountMeta::new_readonly(self.mint, false),
- ]
+ vec![
+ AccountMeta::new(self.account, true),
+ AccountMeta::new_readonly(self.mint, false),
+ ]Committable suggestion skipped: line range outside the PR's diff.
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/update_compressed_mint/instruction.rs (1)
135-143: CPI-write meta-config for authority updates is reasonable; consider future unificationUsing
MintActionMetaConfigCpiWrite { fee_payer: inputs.payer, mint_signer: None, authority: inputs.authority, cpi_context: inputs.cpi_context_pubkey }for authority-only updates makes sense and matches the intent that no mint signer is required on this path.If
MintActionMetaConfigCpiWriteever grows ato_account_metas()helper similar toMintActionMetaConfig, you might later align this with the create/update flows by calling that instead ofget_mint_action_instruction_account_metas_cpi_write(meta_config), but that’s purely a consistency/nicety, not a blocker.
♻️ Duplicate comments (12)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/mod.rs (1)
5-8: Public re-exports still drop the non‑CPI helper; confirm compatibility and migration pathThis module now only re‑exports the CPI helper plus the config types. If any external crates previously pulled in the non‑CPI
get_mint_action_instruction_account_metasvia this module, they will still break on upgrade, even thoughMintActionMetaConfig::to_account_metas()is the new preferred path.If the intent is a clean break, that’s fine, but it’s worth explicitly verifying that no external crates rely on the old symbol, or providing a deprecated compatibility shim (thin wrapper calling
MintActionMetaConfig::to_account_metas()) for one release to ease migration.#!/bin/bash # Scan the workspace for any remaining uses of the old helper name. rg -n "get_mint_action_instruction_account_metas" --type rust || echo "No direct usages found"sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_to_compressed/instruction.rs (1)
10-14: Meta-config refactor is solid; clean up Option handling and unused inputsThe move to
MintActionMetaConfig::new(...).with_mint_compressed_tokens().to_account_metas()is a nice consolidation of account-metas logic for the mint-to-compressed path.Two small follow‑ups here:
- The
cpi_context_pubkey.is_some()+unwrap()pattern is still a bit brittle; matching theOptiondirectly is clearer and avoids any future refactors accidentally separating the check from the unwrap. For example:- let meta_config = if cpi_context_pubkey.is_some() { - MintActionMetaConfig::new_cpi_context( - &instruction_data, - payer, - mint_authority, - cpi_context_pubkey.unwrap(), - )? - } else { + let meta_config = if let Some(cpi_pubkey) = cpi_context_pubkey { + MintActionMetaConfig::new_cpi_context( + &instruction_data, + payer, + mint_authority, + cpi_pubkey, + )? + } else { MintActionMetaConfig::new( payer, mint_authority, state_merkle_tree, input_queue, output_queue_cmint, ) .with_mint_compressed_tokens() };
output_queue_tokens,decompressed_mint_config, andtoken_poolare now destructured as_. If they’re no longer needed for this flow, consider dropping them fromMintToCompressedInputs(or adding a brief comment/TODO) to keep the API surface focused and avoid confusion for callers.Also applies to: 43-57, 75-91, 93-104
sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs (1)
83-101: Use directOptionmatching inmeta_configbranch to avoidunwrapThe switch to
MintActionMetaConfig::new_cpi_context/new_create_mintplus.to_account_metas()is a good cleanup and keeps account-metas logic centralized.You can simplify the CPI/non‑CPI branch and avoid the
is_some+unwrappair by matchingcpi_context_pubkeydirectly, as noted in the earlier review:- let meta_config = if cpi_context_pubkey.is_some() { - MintActionMetaConfig::new_cpi_context( - &instruction_data, - input.payer, - input.mint_authority, - cpi_context_pubkey.unwrap(), - )? - } else { - MintActionMetaConfig::new_create_mint( - input.payer, - input.mint_authority, - input.mint_signer, - input.address_tree_pubkey, - input.output_queue, - ) - }; + let meta_config = if let Some(cpi_pubkey) = cpi_context_pubkey { + MintActionMetaConfig::new_cpi_context( + &instruction_data, + input.payer, + input.mint_authority, + cpi_pubkey, + )? + } else { + MintActionMetaConfig::new_create_mint( + input.payer, + input.mint_authority, + input.mint_signer, + input.address_tree_pubkey, + input.output_queue, + ) + };This keeps the two branches symmetric and removes the chance of drift between the
is_somecheck and theunwrap.sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (1)
80-112: Please resolve the lingering commented-out builder stub.This
with_spl_source_optionalblock was already called out in an earlier review. Leaving a half-implemented pattern in comments keeps the API surface confusing. Either finish the helper (with proper error handling and ownership checks) or drop it so downstream users aren’t tempted to cargo-cult incomplete code.sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs (2)
374-391: CPI write helper omits required base accounts.
get_mint_action_instruction_account_metas_cpi_writeemits metas in the order: light system program, mint signer (optional), authority, fee payer, CPI authority PDA, then the CPI context account. Here we only pass[payer, cpi_context_account, ...ctoken_accounts], so the very first lookup mismatches and the CPI immediately fails. Thread the authority and the default system accounts through this struct and build theaccount_infosslice in the same order as the metas.Apply a change along these lines:
-pub struct MintToCTokenCpiWriteInfos<'info> { - pub payer: AccountInfo<'info>, - pub cpi_context_account: AccountInfo<'info>, - pub ctoken_accounts: Vec<AccountInfo<'info>>, - pub params: MintToCTokenCpiWriteParams, -} +pub struct MintToCTokenCpiWriteInfos<'info> { + pub authority: AccountInfo<'info>, + pub payer: AccountInfo<'info>, + pub system_accounts: crate::ctoken::SystemAccountInfos<'info>, + pub cpi_context_account: AccountInfo<'info>, + pub ctoken_accounts: Vec<AccountInfo<'info>>, + pub params: MintToCTokenCpiWriteParams, +} @@ - let instruction = self.instruction()?; - let mut account_infos = vec![self.payer, self.cpi_context_account]; - account_infos.extend(self.ctoken_accounts); + let instruction = self.instruction()?; + let mut account_infos = vec![ + self.system_accounts.light_system_program, + self.authority, + self.payer, + self.system_accounts.cpi_authority_pda, + self.cpi_context_account, + ]; + account_infos.extend(self.ctoken_accounts); invoke_signed(&instruction, &account_infos, signer_seeds)Also validate in the
From/TryFromimpl thatparams.mint_authoritymatches the providedauthoritykey before forwarding.
286-335: CPI path still misorders account infos.When
cpi_contextis set,MintActionMetaConfig::new_cpi_contextomits the tree/queue metas and instead expects the CPI context account immediately after the system slots. We still append output/state/input before pushingcpi_context_account, so the runtime hitsInstructionError::AccountMismatchthe moment the CPI helper is exercised. Please gate the queue trio behindself.cpi_context.is_none()and push the CPI context account before extending ctoken accounts (apply the same fix ininvoke_signed).Apply this diff to both
invokeandinvoke_signed:- let mut account_infos = vec![ - self.system_accounts.light_system_program, - self.authority, - self.payer, - self.system_accounts.cpi_authority_pda, - self.system_accounts.registered_program_pda, - self.system_accounts.account_compression_authority, - self.system_accounts.account_compression_program, - self.system_accounts.system_program, - self.output_queue, - self.state_tree, - self.input_queue, - ]; - - account_infos.extend(self.ctoken_accounts); - - if let Some(cpi_context_account) = self.cpi_context_account { - account_infos.push(cpi_context_account); - } + let mut account_infos = vec![ + self.system_accounts.light_system_program, + self.authority, + self.payer, + self.system_accounts.cpi_authority_pda, + self.system_accounts.registered_program_pda, + self.system_accounts.account_compression_authority, + self.system_accounts.account_compression_program, + self.system_accounts.system_program, + ]; + + if let Some(cpi_context_account) = self.cpi_context_account { + account_infos.push(cpi_context_account); + } else { + account_infos.push(self.output_queue); + account_infos.push(self.state_tree); + account_infos.push(self.input_queue); + } + + account_infos.extend(self.ctoken_accounts);sdk-libs/compressed-token-sdk/src/ctoken/close.rs (1)
69-88: Missing token programAccountInfoin CPI helpers
CloseAccountInfos::invokeandinvoke_signedstill omitself.token_programfrom theaccount_infosslice, even thoughInstruction::program_idis set to that pubkey. For SPL/ctoken CPIs you must include the program’sAccountInfoin the slice or the runtime will fail dispatching the call.You likely want
account_infosto includeself.token_programas the last element in both branches:pub fn invoke(self) -> Result<(), ProgramError> { let instruction = self.instruction()?; if let Some(rent_sponsor) = self.rent_sponsor { - let account_infos = [self.account, self.destination, self.owner, rent_sponsor]; + let account_infos = [ + self.account, + self.destination, + self.owner, + rent_sponsor, + self.token_program, + ]; invoke(&instruction, &account_infos) } else { - let account_infos = [self.account, self.destination, self.owner]; + let account_infos = [ + self.account, + self.destination, + self.owner, + self.token_program, + ]; invoke(&instruction, &account_infos) } } pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> { let instruction = self.instruction()?; if let Some(rent_sponsor) = self.rent_sponsor { - let account_infos = [self.account, self.destination, self.owner, rent_sponsor]; + let account_infos = [ + self.account, + self.destination, + self.owner, + rent_sponsor, + self.token_program, + ]; invoke_signed(&instruction, &account_infos, signer_seeds) } else { - let account_infos = [self.account, self.destination, self.owner]; + let account_infos = [ + self.account, + self.destination, + self.owner, + self.token_program, + ]; invoke_signed(&instruction, &account_infos, signer_seeds) } }sdk-libs/compressed-token-sdk/src/ctoken/create.rs (1)
40-90: Fix system program meta for compressible accounts and re‑check signer flag for non‑compressible accountsTwo related issues in
CreateCTokenAccount::instruction:
System program meta uses
Pubkey::default()In the compressible branch:
AccountMeta::new_readonly(Pubkey::default(), false), // system_programbut in the CPI helpers you pass
compressible.system_programas the correspondingAccountInfo. That means:
instruction.accounts[4].pubkeyis all‑zeros.- The
AccountInfoat the same index ininvoke/invoke_signedis the real system program account.This mismatch will cause the runtime to reject the instruction (and the ctoken program itself is very likely to check that the supplied system program matches the expected ID).
You should wire the actual system program ID here, e.g. via whatever system‑program constant this workspace exposes (pseudo‑code):
- AccountMeta::new_readonly(Pubkey::default(), false), // system_program + AccountMeta::new_readonly(system_program_id(), false), // system_programwhere
system_program_id()is the appropriate helper/constant for the Solana system program in this repo.Non‑compressible account signer semantics
In the non‑compressible branch you use:
AccountMeta::new(self.account, false),whereas the compressible branch marks
self.accountas a signer:AccountMeta::new(self.account, true),For InitializeAccount3‑style flows it’s common for the token account being initialized to be a signer regardless of extension, so this asymmetry is worth re‑confirming against the on‑chain program’s expectations.
If the ctoken program requires the account to be a signer in both cases, consider:
- vec![ - AccountMeta::new(self.account, false), - AccountMeta::new_readonly(self.mint, false), - ] + vec![ + AccountMeta::new(self.account, true), + AccountMeta::new_readonly(self.mint, false), + ]sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (2)
35-44:compressibleis modelled as optional but ctors always forceSome(...)Both
CreateAssociatedTokenAccountandCreateAssociatedTokenAccount2storecompressible: Option<CompressibleParams>, and the corresponding*Infosstructs carryOption<CompressibleParamsInfos<'info>>. However, all the provided constructors (new,new_with_bump, andCreateAssociatedTokenAccountInfos::new) require a non‑optionalCompressibleParams*and always wrap it inSome(...). The only way to produce a non‑compressible ATA is via manual struct construction, which is easy to miss at the call sites. This is the same concern that was raised in the earlier review.If non‑compressible CTOKEN ATAs are valid, consider either:
- Letting the ctors take
Option<CompressibleParams>/Option<CompressibleParamsInfos<'info>>and propagate that directly, or- Adding explicit helpers like
new_without_compressible(...)andnew_with_bump_without_compressible(...).If non‑compressible ATAs are not valid, changing the field type to
CompressibleParams/CompressibleParamsInfos<'info>would make the API intent clearer.Also applies to: 46-83, 143-152, 154-174, 256-265, 267-303, 364-373
90-103: ATA flows still dropcompress_to_account_pubkey; document or propagate itIn both V1 and V2 builders,
CompressibleExtensionInstructionDataand theFrom<&...Infos> for ...conversions hard‑code:compress_to_account_pubkey: None,ignoring any
compress_to_account_pubkeythat might be present inCompressibleParams/CompressibleParamsInfos<'info>. That’s different from thecreate.rsflow, where this field is propagated from the infos into the instruction data. This matches a concern already raised in a previous review.If ATA creation should never customize
compress_to_account_pubkey, this is fine but deserves an explicit comment (e.g. “ATAs always compress to their own address; overrides are ignored”). If you expect to support non‑default compress targets for ATAs later, it would be safer to propagate the field now for consistency withCreateCTokenAccount.Also applies to: 228-247, 310-324, 431-449
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
63-85: CPI context still emits queue/tree metas with default pubkeys, causing account mismatch
MintActionMetaConfig::new_cpi_contextintentionally sets:tree_pubkey: Pubkey::default(), output_queue: Pubkey::default(), mint_signer: None, input_queue: None, cpi_context: Some(cpi_context_pubkey),but
to_account_metasalways pushesself.output_queueandself.tree_pubkey, and may also pushinput_queue/tokens_out_queue. For CPI callers, helper structs likeCreateCMintAccountInfos::invoke*(and similar mint/transfer helpers) provide real queue/treeAccountInfos in these positions. The result is anInstructionwhose metas contain zeroed pubkeys at those indices, while the suppliedAccountInfos hold real keys — the Solana runtime will reject this withInstructionError::AccountMismatchbefore your program executes. This is exactly the issue called out in the earlier review; it’s still present after the refactor.To fix it, gate queue‑related metas behind the non‑CPI path, along the lines of the earlier suggestion:
- metas.push(AccountMeta::new(self.output_queue, false)); - - metas.push(AccountMeta::new(self.tree_pubkey, false)); - - // input_queue is present when NOT creating a new mint (mint_signer.is_none()) - if self.mint_signer.is_none() { - if let Some(input_queue) = self.input_queue { - metas.push(AccountMeta::new(input_queue, false)); - } - } - - // tokens_out_queue is present when there are MintToCompressed actions - if let Some(tokens_out_queue) = self.tokens_out_queue { - metas.push(AccountMeta::new(tokens_out_queue, false)); - } + if self.cpi_context.is_none() { + metas.push(AccountMeta::new(self.output_queue, false)); + metas.push(AccountMeta::new(self.tree_pubkey, false)); + + // input_queue is present when NOT creating a new mint (mint_signer.is_none()) + if self.mint_signer.is_none() { + if let Some(input_queue) = self.input_queue { + metas.push(AccountMeta::new(input_queue, false)); + } + } + + // tokens_out_queue is present when there are MintToCompressed actions + if let Some(tokens_out_queue) = self.tokens_out_queue { + metas.push(AccountMeta::new(tokens_out_queue, false)); + } + }You’ll also want to ensure the various
*AccountInfos::invoke*helpers only pass queue/tree accounts in the non‑CPI case so the account slices stay aligned.Also applies to: 97-168
sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (1)
206-212: CPI‑write mint path still passes too few and misordered accounts toinvoke_signed
CreateCompressedMintCpiWrite::instructionbuilds a CPI‑write mint action using:let meta_config = MintActionMetaConfigCpiWrite { fee_payer: self.payer, mint_signer: Some(self.mint_signer), authority: self.params.mint_authority, cpi_context: self.cpi_context_pubkey, }; let account_metas = get_mint_action_instruction_account_metas_cpi_write(meta_config);and
get_mint_action_instruction_account_metas_cpi_writeemits metas for:
- Light system program
- Optional mint signer
- Authority (signer)
- Fee payer (signer)
- CPI authority PDA
- CPI context account
But
CreateCompressedMintCpiWriteInfos::invoke_signedcurrently supplies only:let account_infos = [self.mint_signer, self.payer, self.cpi_context_account]; invoke_signed(&instruction, &account_infos, signer_seeds)so the runtime sees fewer accounts than described in the
Instructionand cannot match them to the metas — this will fail immediately with a missing/mismatched account error. This is the same issue called out in the earlier review.You already have
SystemAccountInfos<'info>in this module; a minimal fix is to extendCreateCompressedMintCpiWriteInfosand itsinvoke_signedto pass the full set of accounts expected by the metas, e.g.:pub struct CreateCompressedMintCpiWriteInfos<'info> { - pub mint_signer: AccountInfo<'info>, - pub payer: AccountInfo<'info>, - pub cpi_context_account: AccountInfo<'info>, + pub mint_signer: AccountInfo<'info>, + pub authority: AccountInfo<'info>, + pub payer: AccountInfo<'info>, + pub system_accounts: SystemAccountInfos<'info>, + pub cpi_context_account: AccountInfo<'info>, pub params: CreateCMintCpiWriteParams, } pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> { let instruction = self.instruction()?; - let account_infos = [self.mint_signer, self.payer, self.cpi_context_account]; + let account_infos = [ + self.system_accounts.light_system_program, + self.mint_signer, + self.authority, + self.payer, + self.system_accounts.cpi_authority_pda, + self.cpi_context_account, + ]; invoke_signed(&instruction, &account_infos, signer_seeds) }Adjust the
From<&CreateCompressedMintCpiWriteInfos<'info>> for CreateCompressedMintCpiWriteimpl and call sites accordingly. This will bring the CPI‑write path in line with the account metas it advertises.Also applies to: 229-280, 409-425
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (60)
Cargo.lockis excluded by!**/*.lockand included by noneCargo.tomlis excluded by none and included by noneprogram-tests/compressed-token-test/tests/ctoken/compress_and_close.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/ctoken/create.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/ctoken/create_ata.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/ctoken/create_ata2.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/ctoken/functional.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/ctoken/functional_ata.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/ctoken/shared.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/mint/cpi_context.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/mint/edge_cases.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/mint/failing.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/mint/functional.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/mint/random.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/transfer2/compress_failing.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/transfer2/compress_spl_failing.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/transfer2/decompress_failing.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/transfer2/no_system_program_cpi_failing.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/transfer2/shared.rsis excluded by none and included by noneprogram-tests/compressed-token-test/tests/transfer2/spl_ctoken.rsis excluded by none and included by noneprogram-tests/registry-test/tests/compressible.rsis excluded by none and included by noneprogram-tests/utils/src/assert_create_token_account.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/src/instruction_accounts.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/src/instructions/create_user_record_and_game_session.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/src/instructions/decompress_accounts_idempotent.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/tests/game_session_tests.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/tests/helpers.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/tests/idempotency_tests.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/tests/multi_account_tests.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/Cargo.lockis excluded by!**/*.lockand included by nonesdk-tests/sdk-ctoken-test/Cargo.tomlis excluded by none and included by nonesdk-tests/sdk-ctoken-test/README.mdis excluded by none and included by nonesdk-tests/sdk-ctoken-test/Xargo.tomlis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/close.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/create_ata.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/create_ata2.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/create_cmint.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/create_token_account.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/lib.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/mint_to_ctoken.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/transfer.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/transfer_interface.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/transfer_spl_ctoken.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/shared.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_close.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_create_ata.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_create_ata_v2.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_create_cmint.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_create_token_account.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_mint_to_ctoken.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_transfer.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_transfer_interface.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_transfer_spl_ctoken.rsis excluded by none and included by nonesdk-tests/sdk-token-test/src/process_compress_full_and_close.rsis excluded by none and included by nonesdk-tests/sdk-token-test/src/process_create_ctoken_with_compress_to_pubkey.rsis excluded by none and included by nonesdk-tests/sdk-token-test/tests/compress_and_close_cpi.rsis excluded by none and included by nonesdk-tests/sdk-token-test/tests/decompress_full_cpi.rsis excluded by none and included by nonesdk-tests/sdk-token-test/tests/pda_ctoken.rsis excluded by none and included by nonesdk-tests/sdk-token-test/tests/test_4_transfer2.rsis excluded by none and included by nonesdk-tests/sdk-token-test/tests/test_compress_full_and_close.rsis excluded by none and included by none
📒 Files selected for processing (31)
program-libs/compressed-account/src/instruction_data/traits.rs(1 hunks)programs/compressed-token/program/src/mint_action/accounts.rs(1 hunks)programs/compressed-token/program/src/mint_action/processor.rs(0 hunks)sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs(1 hunks)sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs(3 hunks)sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/mod.rs(1 hunks)sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_to_compressed/instruction.rs(3 hunks)sdk-libs/compressed-token-sdk/src/compressed_token/v2/update_compressed_mint/instruction.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/close.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/compressible.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/create.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/create_associated_token_account.rs(0 hunks)sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/instruction.rs(0 hunks)sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/mod.rs(0 hunks)sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/mod.rs(2 hunks)sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken.rs(0 hunks)sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken_spl.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs(4 hunks)sdk-libs/compressed-token-sdk/src/ctoken/transfer_spl_ctoken.rs(1 hunks)sdk-libs/compressed-token-sdk/src/error.rs(1 hunks)sdk-libs/compressed-token-sdk/src/lib.rs(1 hunks)sdk-libs/compressed-token-sdk/tests/create_associated_token_account.rs(3 hunks)sdk-libs/token-client/src/actions/create_compressible_token_account.rs(2 hunks)sdk-libs/token-client/src/actions/mint_action.rs(1 hunks)sdk-libs/token-client/src/actions/transfer2/ctoken_to_spl.rs(1 hunks)sdk-libs/token-client/src/actions/transfer2/spl_to_ctoken.rs(3 hunks)sdk-libs/token-client/src/instructions/create_mint.rs(2 hunks)sdk-libs/token-client/src/instructions/mint_action.rs(3 hunks)
💤 Files with no reviewable changes (5)
- sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/mod.rs
- programs/compressed-token/program/src/mint_action/processor.rs
- sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken.rs
- sdk-libs/compressed-token-sdk/src/ctoken/create_token_account/instruction.rs
- sdk-libs/compressed-token-sdk/src/ctoken/create_associated_token_account.rs
🧰 Additional context used
🧬 Code graph analysis (16)
sdk-libs/token-client/src/actions/transfer2/ctoken_to_spl.rs (1)
sdk-libs/compressed-token-sdk/src/token_pool.rs (1)
find_token_pool_pda_with_index(20-28)
sdk-libs/token-client/src/instructions/create_mint.rs (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs (2)
derive_compressed_mint_address(193-202)find_spl_mint_address(212-217)
sdk-libs/token-client/src/actions/mint_action.rs (1)
sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (1)
derive_ctoken_ata(20-29)
sdk-libs/compressed-token-sdk/src/ctoken/create.rs (2)
sdk-libs/compressed-token-sdk/src/ctoken/compressible.rs (2)
new(33-39)new(57-73)sdk-libs/compressed-token-sdk/src/error.rs (3)
from(77-79)from(83-85)from(89-122)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken_spl.rs (3)
sdk-libs/compressed-token-sdk/src/error.rs (3)
from(77-79)from(83-85)from(89-122)sdk-libs/compressed-token-sdk/src/compressed_token/v2/account2.rs (2)
compress_ctoken(169-190)decompress_spl(250-279)sdk-libs/compressed-token-sdk/src/compressed_token/v2/transfer2/account_metas.rs (1)
new_decompressed_accounts_only(33-46)
sdk-libs/token-client/src/actions/transfer2/spl_to_ctoken.rs (1)
sdk-libs/compressed-token-sdk/src/token_pool.rs (1)
find_token_pool_pda_with_index(20-28)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_to_compressed/instruction.rs (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
new(43-61)
sdk-libs/token-client/src/instructions/mint_action.rs (2)
sdk-libs/token-client/src/actions/mint_action.rs (1)
mint_action(24-59)program-libs/ctoken-types/src/instructions/mint_action/mint_to_compressed.rs (2)
new(14-19)new(30-35)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (2)
sdk-libs/token-client/src/actions/ctoken_transfer.rs (1)
transfer_ctoken(20-38)sdk-libs/compressed-token-sdk/src/utils.rs (1)
is_ctoken_account(22-37)
sdk-libs/compressed-token-sdk/tests/create_associated_token_account.rs (2)
sdk-libs/compressed-token-sdk/src/ctoken/create_ata.rs (1)
derive_ctoken_ata(20-29)sdk-libs/compressed-token-sdk/src/ctoken/close.rs (1)
new(18-26)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/mod.rs (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
get_mint_action_instruction_account_metas_cpi_write(181-209)
sdk-libs/compressed-token-sdk/src/ctoken/mod.rs (2)
sdk-libs/sdk/src/compressible/close.rs (1)
close(6-40)sdk-libs/token-client/src/actions/ctoken_transfer.rs (1)
transfer_ctoken(20-38)
sdk-libs/token-client/src/actions/create_compressible_token_account.rs (3)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
new(43-61)sdk-libs/compressed-token-sdk/src/ctoken/close.rs (1)
new(18-26)sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (1)
new(40-57)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
sdk-libs/token-client/src/actions/mint_action.rs (1)
mint_action(24-59)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs (1)
sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs (1)
new_create_mint(22-40)
sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (4)
sdk-libs/compressed-token-sdk/src/ctoken/create.rs (6)
invoke(122-138)new(24-38)new(102-116)instruction(40-90)instruction(118-120)from(160-178)program-libs/compressed-account/src/instruction_data/traits.rs (6)
cpi_context(58-58)data(26-34)data(87-87)data(108-108)address(84-84)address(105-105)program-libs/ctoken-types/src/instructions/mint_action/builder.rs (2)
new_mint(44-63)new_mint_write_to_cpi_context(65-84)program-libs/compressed-account/src/pubkey.rs (1)
new_from_array(79-81)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: programs (system-cpi-test-v2-functional-account-infos, ["cargo-test-sbf -p system-cpi-v2-test -- ...
- GitHub Check: programs (system-cpi-test-v2-functional-read-only, ["cargo-test-sbf -p system-cpi-v2-test -- func...
- GitHub Check: programs (system-cpi-test, ["cargo-test-sbf -p system-cpi-test", "cargo test -p light-system-prog...
- GitHub Check: programs (account-compression-and-registry, ["cargo-test-sbf -p account-compression-test", "cargo...
- GitHub Check: Test batched-merkle-tree-simulate
- GitHub Check: Test program-libs-slow
- GitHub Check: Test program-libs-fast
- GitHub Check: Forester e2e test
🔇 Additional comments (13)
program-libs/compressed-account/src/instruction_data/traits.rs (1)
30-32: Readability improvement: Good separation of concerns.Adding a blank line between discriminator serialization and inputs serialization cleanly separates two distinct logical operations. This aligns well with Rust conventions and improves code clarity without affecting functionality.
sdk-libs/compressed-token-sdk/src/error.rs (1)
114-114: Error code reassignment verified—changes are sound.The removed error variants (
CreateMintDataRequiredandCreateMintMustBeNone) are not referenced anywhere else in the codebase, confirming the removal is clean and complete. The error code reassignment forCpiContextRequiredfrom 17026 to 17024 maintains sequential numbering and is properly isolated to the error mapping definition.sdk-libs/token-client/src/actions/mint_action.rs (1)
101-112: Switch toctoken::derive_ctoken_atakeeps behavior consistent and centralizes ATA derivationUsing
derive_ctoken_atafrom the ctoken module in this MintToCToken branch keeps the call site simple and aligns with the new SDK builders, while still deriving the ATA from the recipient pubkey andspl_mint_pda. No additional issues from this change.sdk-libs/token-client/src/actions/transfer2/ctoken_to_spl.rs (1)
5-7: UpdatedTransferCtokenToSplimport matches the new public ctoken APIPointing the import directly at
ctoken::TransferCtokenToSpl(instead of viatransfer_interface) matches the refactored SDK layout and leaves the transfer call site unchanged. Looks good.sdk-libs/compressed-token-sdk/src/lib.rs (1)
14-15: Re‑exportingCompressedProofat the crate root is a reasonable API ergonomicSurfacing
CompressedProofhere aligns with how other core types are re‑exported and makes it easier for downstream users to work with compressed proofs without depending onlight_compressed_accountdirectly. Just keep in mind this symbol is now part of your stable public surface for semver purposes.sdk-libs/token-client/src/actions/transfer2/spl_to_ctoken.rs (1)
5-7: Renamed SPL→ctoken destination wiring looks consistentThe switch to
ctoken::TransferSplToCtokenand the rename todestination_ctoken_accountare applied consistently in the function signature and struct init; SPL source vs ctoken destination are now clearly distinguished with no behavior change.Also applies to: 16-23, 36-47
sdk-libs/compressed-token-sdk/src/compressed_token/v2/create_compressed_mint/instruction.rs (1)
163-170: CPI-write meta-config update matches newMintActionMetaConfigCpiWriteshapeThe updated
MintActionMetaConfigCpiWriteliteral (droppingmint_needs_to_signand keepingmint_signer: Some(input.mint_signer)) lines up with the new struct definition and the fact that this path always has a mint signer. Continuing to delegate toget_mint_action_instruction_account_metas_cpi_writehere is fine given the specialized CPI-write behavior.sdk-libs/compressed-token-sdk/src/compressed_token/v2/update_compressed_mint/instruction.rs (1)
66-75: Update path’s meta-config wiring looks correct
MintActionMetaConfig::new(input.payer, input.authority, input.in_merkle_tree, input.in_output_queue, input.out_output_queue)matches thenewsignature (payer, authority, state tree, input queue, output queue), and switching to.to_account_metas()keeps account metas centralized with the rest of the mint_action flows. No issues here.sdk-libs/token-client/src/instructions/create_mint.rs (1)
64-76: Unwrap on RPC proof is a legitimate panic risk; verify the versioning strategyYour first concern about the
.unwrap()is spot-on. The function already establishes a clean error handling pattern at line 88 withRpcError::CustomError(), so line 71's direct unwrap breaks that contract. If the indexer returnsNone(due to misconfiguration, network hiccup, or indexer glitch), you'll panic instead of propagating a typed error—exactly what you're flagging.For the hardcoded
version: 3: my search found noVERSIONorCTOKEN_VERSIONconstants in the codebase. That doesn't mean one shouldn't exist, but it does mean the current approach warrants a design decision. Before committing the fix:
- Check the Light Protocol token types architecture (
light-ctoken-types) to understand versioning intent—is version truly immutable per implementation, or could it evolve?- If versioning should be dynamic, define a constant in the appropriate types module and reference it.
- If version 3 is intentionally locked, add a comment explaining why (e.g., "Hardcoded for CreateCMint V3 specification").
The proof handling fix (converting unwrap to
ok_or_else(...)) is the critical fix to implement immediately. The version approach is a secondary decision based on your protocol's versioning contract.sdk-libs/compressed-token-sdk/tests/create_associated_token_account.rs (1)
1-102: Tests nicely cover the new ATA builder surfaceThe updated tests exercise:
- Discriminator selection for regular vs idempotent variants.
- Instruction data consistency between the two.
new_with_bumpbehavior, including idempotent mode.- Account count for the compressible configuration.
This gives good confidence in the
CreateAssociatedTokenAccountAPI and its wire format; no issues spotted here.sdk-libs/compressed-token-sdk/src/ctoken/transfer_spl_ctoken.rs (1)
43-78: The review comment's account mismatch claim is technically incorrect, but the underlying design concern is validAfter examining the code, the account order and count actually do align:
get_transfer2_instruction_account_metas()fordecompressed_accounts_only=truebuilds metas in order:CPI_AUTHORITY_PDA,fee_payer, then the 6packed_accounts(8 total)invoke()'saccount_infosslice is arranged identically:compressed_token_program_authority,payer, then the same 6 packed accounts (8 total)The accounts match if and only if
compressed_token_program_authorityis correctly initialized to theCPI_AUTHORITY_PDAaccount. The code's comment already documents this dependency: "Account order must match instruction metas: cpi_authority_pda, fee_payer, packed_accounts..."However, there is a real design issue: this constraint is implicit and never validated. The
TransferSplToCtokenAccountInfosstruct acceptscompressed_token_program_authorityas a free parameter without enforcing or documenting that it must be the CPI authority. If a caller passes the wrong account, the CPI will fail at runtime without a compile-time or clear validation error.Consider:
- Either explicitly derive/validate that
compressed_token_program_authoritymust beCPI_AUTHORITY_PDAwithin the instruction building logic- Or document this constraint prominently in the struct and all call sites
- Or remove the parameter from the struct and hardcode
CPI_AUTHORITY_PDAdirectlyLikely an incorrect or invalid review comment.
sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken_spl.rs (1)
42-77: <!-- [scratchpad_start]
[task review_transfer_ctoken_spl verification FINAL]
Compared SPL→ctoken and ctoken→SPL structures and traced full meta path.[CRITICAL FINDINGS]
Both TransferSplToCtoken and TransferCtokenToSpl have identical structure:
- Inner struct WITHOUT compressed_token_program_authority
- AccountInfos wrapper WITH compressed_token_program_authority
- invoke/invoke_signed prepend compressed_token_program_authority to account_infos
Meta construction path is IDENTICAL for both:
- packed_accounts (6 items): [mint, account, account, authority, pool, program]
- Passed to new_decompressed_accounts_only(payer, packed_accounts)
- get_transfer2_instruction_account_metas builds: [CPI_AUTHORITY_PDA, payer, ...packed_accounts]
CRITICAL: CPI_AUTHORITY_PDA IS in the metas
- Lines 110-113 of account_metas.rs push CPI_AUTHORITY_PDA for decompressed_accounts_only=true
- This happens automatically, not via Transfer2Config parameter
- The reviewer's claim that it's "not propagated" is WRONG
account_infos ordering MATCHES metas ordering perfectly:
- Instruction metas: [CPI_AUTHORITY_PDA, payer, mint, src/dst, authority, pool, spl_token_program]
- account_infos: [compressed_token_program_authority, payer, mint, src/dst, authority, pool, spl_token_program]
- The compressed_token_program_authority field IS the CPI_AUTHORITY_PDA
Both directions (SPL→ctoken and ctoken→SPL) have IDENTICAL structure and comments
- Comments explicitly state: "Account order must match instruction metas: cpi_authority_pda, fee_payer, packed_accounts..."
- This shows intentional correct design
[conclusion]
The review comment is INCORRECT. The code is working as designed:
- CPI authority IS in the metas (added by get_transfer2_instruction_account_metas)
- account_infos ordering DOES match instruction metas
- No mismatch exists
- The helpers are safe to use
[done]
</scratchpad_end] -->The review comment is incorrect; the code is actually correct.
Your implementation properly aligns
account_infoswith the instruction metas. TheCPI_AUTHORITY_PDAis automatically added byget_transfer2_instruction_account_metas()whendecompressed_accounts_only=true(line 110-113 of account_metas.rs), even though it's not explicitly passed throughTransfer2Config. This matches yourcompressed_token_program_authorityfield placement and your explicit comment about ordering.The meta construction path is:
new_decompressed_accounts_only(payer, packed_accounts)setscpi_context: Noneanddecompressed_accounts_only: trueget_transfer2_instruction_account_metas()seesdecompressed_accounts_only=trueand automatically pushesCPI_AUTHORITY_PDAfirst (readonly, not signer), thenpayer(writable, signer), then the 6 packed accounts- Your
invoke()correctly mirrors this:compressed_token_program_authority, thenpayer, then the packed accountsBoth your ctoken→SPL and SPL→ctoken paths use identical ordering logic and are consistent. The runtime will accept these CPIs because the keys and flags match the instruction metas.
sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (1)
25-52: CreateCMint parameter structs and address derivation helpers look soundThe
CreateCMintParams/CreateCMintCpiWriteParamsstructs capture the expected knobs (decimals, version, authorities, root index, compression address, optional extensions) with a reasonable default of version 3, and the helper functions:
derive_compressed_mint_address(...)derive_cmint_from_spl_mint(...)find_spl_mint_address(...)all follow the expected pattern of deriving addresses from the SPL mint (or mint seed), address tree, and
COMPRESSED_TOKEN_PROGRAM_ID. Assuming these seeds match the on‑chain program’s convention, the derivations should be stable and predictable.Also applies to: 156-200, 443-470
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (4)
sdk-libs/compressed-token-sdk/src/ctoken/mod.rs (1)
31-77: Document invariants for SystemAccountInfos/SystemAccounts and versioned PDAs
SystemAccountInfos<'info>/SystemAccountsnicely reflect the fixed Light Protocol base accounts, and the newCOMPRESSIBLE_CONFIG_V1/RENT_SPONSORconstants make those PDAs explicit. The trade‑off is that:
- The field order in
SystemAccountInfos/SystemAccountsmust stay in sync withCTokenDefaultAccountsand the order used by mint/transfer account‑meta builders, andCOMPRESSIBLE_CONFIG_V1andRENT_SPONSORare now baked‑in, network‑specific PDAs (v1).It would help future maintainers if the invariants were documented, for example:
/// Base Light Protocol system accounts used by all ctoken instructions. /// Field order must match `CTokenDefaultAccounts` and the account meta layout. pub struct SystemAccountInfos<'info> { ... } /// v1 global compressible config PDA; bump this and keep old constants around /// if the on-chain config layout changes. pub const COMPRESSIBLE_CONFIG_V1: Pubkey = /* ... */;This mirrors an earlier nit about documenting these invariants and makes future upgrades less error‑prone.
Also applies to: 83-86, 114-120
sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs (2)
263-336: AccountInfo ordering for MintToCTokenInfos in CPI-context mode likely still mismatches to_account_metasIn
MintToCTokenInfos::invoke{,_signed}you always push:
- Light system + authority + payer + Light base PDAs,
- Optional
cpi_context_account,output_queue,state_tree,input_queue,- Then all
ctoken_accounts.However, in the CPI-context path
MintToCToken::instructionbuilds its metas via:let meta_config = MintActionMetaConfig::new_cpi_context( &instruction_data, self.payer, self.params.mint_authority, cpi_context_pubkey, )?; let account_metas = meta_config.to_account_metas();and
MintActionMetaConfig::new_cpi_contextinitializes:Ok(Self { fee_payer, authority, tree_pubkey: Pubkey::default(), output_queue: Pubkey::default(), mint_signer: None, input_queue: None, tokens_out_queue: None, cpi_context: Some(cpi_context_pubkey), ctoken_accounts: Vec::new(), })So in CPI mode the metas will contain just the base Light accounts +
cpi_context, not the queues, and anyctoken_accountsare not coming from this config. Pushing queues (and potentially extra accounts) here risksInstructionError::AccountMismatchwhen the metas andAccountInfoslice diverge.A safer layout for CPI-context calls is:
- let mut account_infos = vec![ - self.system_accounts.light_system_program, - self.authority, // authority - self.payer, // fee_payer - self.system_accounts.cpi_authority_pda, - self.system_accounts.registered_program_pda, - self.system_accounts.account_compression_authority, - self.system_accounts.account_compression_program, - self.system_accounts.system_program, - ]; - - if let Some(cpi_context_account) = self.cpi_context_account { - account_infos.push(cpi_context_account); - } - - account_infos.push(self.output_queue); - account_infos.push(self.state_tree); - account_infos.push(self.input_queue); - account_infos.extend(self.ctoken_accounts); + let mut account_infos = vec![ + self.system_accounts.light_system_program, + self.authority, // authority + self.payer, // fee_payer + self.system_accounts.cpi_authority_pda, + self.system_accounts.registered_program_pda, + self.system_accounts.account_compression_authority, + self.system_accounts.account_compression_program, + self.system_accounts.system_program, + ]; + + if let Some(cpi_context_account) = self.cpi_context_account { + account_infos.push(cpi_context_account); + } + + // Only queues are used in the non-CPI path; in CPI-context mode + // the metas do not include them. + if self.cpi_context.is_none() { + account_infos.push(self.output_queue); + account_infos.push(self.state_tree); + account_infos.push(self.input_queue); + } + + account_infos.extend(self.ctoken_accounts);Apply the same pattern in
invoke_signed. This mirrors howMintActionMetaConfig::to_account_metasdistinguishes CPI vs non‑CPI modes and avoids reintroducing the mismatch that a previous review comment already highlighted.#!/bin/bash # Sanity-check that the number and order of metas from MintActionMetaConfig # match the AccountInfo slice built in MintToCTokenInfos for both modes. rg -n "impl MintActionMetaConfig" sdk-libs/compressed-token-sdk/src -C5 rg -n "to_account_metas" sdk-libs/compressed-token-sdk/src -C5 rg -n "MintToCTokenInfos" sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs -n -C5Also applies to: 338-368
374-391: CPI-write helper still doesn’t supply the base accounts expected by get_mint_action_instruction_account_metas_cpi_write
get_mint_action_instruction_account_metas_cpi_writeproduces metas in this order (withmint_signercurrentlyNone):
light_system_program(fromCTokenDefaultAccounts),authority(mint signer / authority),fee_payer,cpi_authority_pda,cpi_context.But
MintToCTokenCpiWriteInfos::invoke_signedonly supplies:let mut account_infos = vec![self.payer, self.cpi_context_account]; account_infos.extend(self.ctoken_accounts);This will immediately misalign metas vs accounts and trigger
InstructionError::AccountMismatchat runtime.You need
MintToCTokenCpiWriteInfosto carry the same base accounts and feed them in the proper order, e.g.:-pub struct MintToCTokenCpiWriteInfos<'info> { - pub payer: AccountInfo<'info>, - pub cpi_context_account: AccountInfo<'info>, - pub ctoken_accounts: Vec<AccountInfo<'info>>, - pub params: MintToCTokenCpiWriteParams, -} +pub struct MintToCTokenCpiWriteInfos<'info> { + /// Mint authority / instruction authority (matches params.mint_authority). + pub authority: AccountInfo<'info>, + /// Fee payer. + pub payer: AccountInfo<'info>, + /// Light system accounts (must align with CTokenDefaultAccounts). + pub system_accounts: crate::ctoken::SystemAccountInfos<'info>, + /// CPI context account. + pub cpi_context_account: AccountInfo<'info>, + /// Any additional ctoken accounts used by the CPI context. + pub ctoken_accounts: Vec<AccountInfo<'info>>, + pub params: MintToCTokenCpiWriteParams, +} @@ - pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> { - let instruction = self.instruction()?; - let mut account_infos = vec![self.payer, self.cpi_context_account]; - account_infos.extend(self.ctoken_accounts); - invoke_signed(&instruction, &account_infos, signer_seeds) - } + pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> { + let instruction = self.instruction()?; + // Must mirror get_mint_action_instruction_account_metas_cpi_write + let mut account_infos = vec![ + self.system_accounts.light_system_program, + self.authority, + self.payer, + self.system_accounts.cpi_authority_pda, + self.cpi_context_account, + ]; + account_infos.extend(self.ctoken_accounts); + invoke_signed(&instruction, &account_infos, signer_seeds) + } @@ -impl<'info> From<&MintToCTokenCpiWriteInfos<'info>> for MintToCTokenCpiWrite { +impl<'info> From<&MintToCTokenCpiWriteInfos<'info>> for MintToCTokenCpiWrite { fn from(account_infos: &MintToCTokenCpiWriteInfos<'info>) -> Self { Self { payer: *account_infos.payer.key, cpi_context_pubkey: *account_infos.cpi_context_account.key, ctoken_accounts: account_infos .ctoken_accounts .iter() .map(|acc| *acc.key) .collect(), params: account_infos.params.clone(), } } }Call sites will need to be updated to supply
authorityandsystem_accounts, mirroring howMintToCTokenInfosis already structured.This exact problem was flagged earlier; the current code regresses back to the broken layout.
#!/bin/bash # Grep for MintToCTokenCpiWriteInfos usage and ensure all call sites # can supply authority + system_accounts in the required order. rg -n "MintToCTokenCpiWriteInfos" -C3 rg -n "get_mint_action_instruction_account_metas_cpi_write" sdk-libs/compressed-token-sdk/src -C5Also applies to: 394-406
sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (1)
90-143: Fix account ordering mismatch betweento_account_metas()andinvoke()methods.The current implementation has inconsistent account ordering when CPI context is present. In
MintActionMetaConfig::to_account_metas()(sdk-libs/compressed-token-sdk/src/compressed_token/v2/mint_action/account_metas.rs, lines 99–149), the optionalcpi_contextis inserted beforeoutput_queueandtree_pubkey. However, inCreateCMintAccountInfos::invoke()andinvoke_signed()(sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs, lines 321–341 and 346–366), these accounts are pushed afterward.When
cpi_contextisSome, the account vectors differ:
to_account_metas():[…system_program, cpi_context, output_queue, tree_pubkey]invoke():[…system_program, output_queue, tree_pubkey, cpi_context]This violates the stated invariant in both
invoke()methods' comments ("Account order must match"). Reorder the accounts ininvoke()andinvoke_signed()to insertcpi_contextbeforeoutput_queueandtree_pubkey, matchingto_account_metas()exactly.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (12)
.github/workflows/sdk-tests.ymlis excluded by none and included by noneCargo.lockis excluded by!**/*.lockand included by noneCargo.tomlis excluded by none and included by nonesdk-tests/sdk-compressible-test/src/instruction_accounts.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/src/instructions/create_user_record_and_game_session.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/src/instructions/decompress_accounts_idempotent.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/tests/game_session_tests.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/tests/helpers.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/tests/idempotency_tests.rsis excluded by none and included by nonesdk-tests/sdk-compressible-test/tests/multi_account_tests.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/transfer_interface.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/test_create_cmint.rsis excluded by none and included by none
📒 Files selected for processing (6)
sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/mod.rs(2 hunks)sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs(7 hunks)sdk-libs/compressed-token-sdk/src/error.rs(2 hunks)sdk-libs/compressed-token-sdk/src/lib.rs(1 hunks)
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/decompress_context.rs : DecompressContext implementation should generate account accessor methods, implement PDA/token separation logic, and delegate token processing
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/decompress_context.rs : DecompressContext implementation should generate account accessor methods, implement PDA/token separation logic, and delegate token processing
Applied to files:
sdk-libs/compressed-token-sdk/src/lib.rssdk-libs/compressed-token-sdk/src/ctoken/mod.rssdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rssdk-libs/compressed-token-sdk/src/error.rssdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rssdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/*.rs : Module structure in Rust should follow the documented organization: mod.rs for module declarations, traits.rs for core trait implementations (HasCompressionInfo, CompressAs, Compressible), pack_unpack.rs for Pubkey compression and Pack/Unpack traits, variant_enum.rs for account variant enums, instructions.rs for instruction handlers, seed_providers.rs for PDA seed derivation, and decompress_context.rs for decompression trait implementations
Applied to files:
sdk-libs/compressed-token-sdk/src/lib.rssdk-libs/compressed-token-sdk/src/ctoken/mod.rssdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rssdk-libs/compressed-token-sdk/src/error.rssdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rssdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/pack_unpack.rs : Pack/Unpack trait implementations should compress Pubkey fields by converting them to u8 indices in generated PackedXxx structs for serialization efficiency
Applied to files:
sdk-libs/compressed-token-sdk/src/lib.rssdk-libs/compressed-token-sdk/src/ctoken/mod.rssdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/variant_enum.rs : CompressedAccountVariant enum generation should implement all required traits: Default, DataHasher, Size, Pack, and Unpack, along with a CompressedAccountData wrapper struct
Applied to files:
sdk-libs/compressed-token-sdk/src/lib.rssdk-libs/compressed-token-sdk/src/ctoken/mod.rssdk-libs/compressed-token-sdk/src/error.rssdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rssdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/instructions.rs : Compress instruction handler should be PDA-only, with ctokens compressed via registry; Decompress instruction handler should support full PDA + ctoken support
Applied to files:
sdk-libs/compressed-token-sdk/src/lib.rssdk-libs/compressed-token-sdk/src/ctoken/mod.rssdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rssdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/traits.rs : HasCompressionInfo trait should provide CompressionInfo field access; CompressAs trait should provide field-level compression control; Compressible trait should bundle Size + HasCompressionInfo + CompressAs
Applied to files:
sdk-libs/compressed-token-sdk/src/lib.rssdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/seed_providers.rs : Seed providers should implement PDA seed provider functionality with CToken seed provider supporting both account and authority derivation, along with client-side seed functions for off-chain use
Applied to files:
sdk-libs/compressed-token-sdk/src/lib.rssdk-libs/compressed-token-sdk/src/ctoken/mod.rssdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rssdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rssdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs
🧬 Code graph analysis (3)
sdk-libs/compressed-token-sdk/src/ctoken/mod.rs (4)
sdk-libs/sdk/src/compressible/close.rs (1)
close(6-43)sdk-libs/sdk/src/compressible/decompress_runtime.rs (1)
compressible(204-204)sdk-libs/token-client/src/actions/ctoken_transfer.rs (1)
transfer_ctoken(20-38)sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (1)
default(39-51)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (1)
sdk-libs/compressed-token-sdk/src/utils.rs (1)
is_ctoken_account(22-37)
sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs (1)
sdk-libs/compressed-token-sdk/src/error.rs (3)
from(85-87)from(91-93)from(97-134)
🪛 GitHub Actions: lint
sdk-libs/compressed-token-sdk/src/lib.rs
[error] 12-12: Diff in file detected during linting step: changes to 'pub use light_compressed_account::instruction_data::compressed_proof::CompressedProof' appear with a +/- context. Process exited with code 1. Command: nx run @lightprotocol/sdk-anchor-test:lint.
🔇 Additional comments (13)
sdk-libs/compressed-token-sdk/src/error.rs (1)
96-126: New SPL-interface-related error codes and mappings look consistentThe added variants (
SplInterfaceRequired,IncompleteSplInterface,MissingMintAccount,MissingSplTokenProgram,MissingTokenPoolPda,MissingTokenPoolPdaBump) are all covered in theFrom<TokenSdkError> for u32match, with contiguous codes and no gaps. This keeps the on‑chain encoding consistent with the rest of the error enum.sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (3)
4-9: Use of typed account-info wrappers for transfer flows looks goodImporting the three account-info structs (
TransferCtokenAccountInfos,TransferCtokenToSplAccountInfos,TransferSplToCtokenAccountInfos) andis_ctoken_accountcentralizes the transfer logic cleanly. This keeps the interface layer small and focused on routing.
11-27: SplInterface and TransferInterface shapes are sensibleFactoring SPL‑side state into
SplInterface<'info>and holding it as anOptioninsideTransferInterface<'info>gives a clear separation between “pure ctoken” and “ctoken<->SPL bridge” paths. Theamountplacement and thenew(...)constructor are straightforward and make the builder easy to use.Also applies to: 29-54
130-138: Destination ctoken account naming matches the SPL→ctoken helpersRenaming the field passed into
TransferSplToCtokenAccountInfosasdestination_ctoken_accountimproves clarity and matches the helper’s expected field names, which should help avoid accidental account swaps.Also applies to: 199-207
sdk-libs/compressed-token-sdk/src/ctoken/mod.rs (1)
1-29: ctoken module re-export surface is cohesivePulling all instruction builders, params, and transfer interfaces into this
ctokenmodule viapub use(close/create*/mint_to/transfer*) creates a clean, single import surface for downstream users and tests. The inclusion of the SPL bridge types (SplInterface,TransferInterface,TransferCtokenToSpl*,TransferSplToCtoken*) also makes the new flows discoverable.sdk-libs/compressed-token-sdk/src/ctoken/mint_to.rs (3)
22-55: MintToCTokenParams and MintToCToken builder are well-structuredThe params + builder split is clear:
MintToCTokenParamsowns the mint inputs, actions, authority, and proof with a small ergonomicnew+add_mint_to_actionAPI.MintToCToken::instructioncorrectly wiresMintActionCompressedInstructionData(including proof and optional CPI context) intoMintActionMetaConfig::{new,new_cpi_context}and defers toto_account_metas, handling Borsh IO errors viaProgramError::BorshIoError.The overall shape is sound and keeps instruction construction logic localized.
Also applies to: 61-147
153-187: CPI-write params and builder logic are consistent with meta-config helper
MintToCTokenCpiWriteParamsandMintToCTokenCpiWritemirror the non‑CPI flow cleanly:
- You validate the CPI context flags before building the instruction.
- You intentionally omit a proof (
None) in the CPI-write variant.MintActionMetaConfigCpiWriteis filled consistently withfee_payer,authority, andcpi_context, and account metas are derived exclusively viaget_mint_action_instruction_account_metas_cpi_write.The control flow here looks correct; the remaining risk is in how the accompanying
MintToCTokenCpiWriteInfosfeedsAccountInfos toinvoke_signed(see separate comment).Also applies to: 192-257
338-368: Authority/mint_authority consistency check in TryFrom is a good guardrailThe
TryFrom<&MintToCTokenInfos<'info>> for MintToCTokenimplementation verifies thatparams.mint_authoritymatches theauthorityaccount key and logs a human‑readable message before returningProgramError::InvalidAccountData. The correspondingFrom<&MintToCTokenCpiWriteInfos<'info>>keeps the CPI-write builder free ofAccountInfoconcerns.These conversions are a solid pattern for separating account validation from instruction construction.
Also applies to: 394-406
sdk-libs/compressed-token-sdk/src/lib.rs (1)
15-15: The CompressedProof re-export is correctly formatted; verify the actual CI error before making changesAfter examining the codebase, the
pub usestatement at line 15 insdk-libs/compressed-token-sdk/src/lib.rsis syntactically sound and follows standard Rust re-export patterns. The file has no uncommitted changes and the code matches project conventions.The concern appears to stem from a reported CI lint error in the
nx run @lightprotocol/sdk-anchor-test:lintstep. However:
- The
nxcommand is a TypeScript/JavaScript monorepo tool, not available in the Rust environment we examined- The
sdk-anchor-testdirectory is currently a scaffolding stub with no actual source files- The Rust code itself is already properly formatted with no outstanding diffs
Before re-running formatters (which may not resolve a TypeScript-layer issue), check your CI logs directly to confirm whether the error is still present and what it actually reports. If the error persists, it may be infrastructure or TypeScript-side configuration, not a Rust formatting problem.
sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (4)
321-369: Account ordering is correct but fragile.The
invoke()andinvoke_signed()methods correctly assemble accounts in the order expected byMintActionMetaConfig::to_account_metas(). However, this manual array construction is fragile—if the meta generation logic changes, these will silently break at runtime withInstructionError::AccountMismatch.Consider adding a compile-time or integration test that verifies the account ordering remains synchronized between the builder's instruction method and the account infos' invoke methods.
</comment_end>
372-397: LGTM: Authority validation is appropriate.The
TryFromimplementation correctly validates that themint_authorityparameter matches the provided authority account, preventing configuration errors that would cause runtime failures.</comment_end>
417-430: LGTM: CPI write account ordering is now correct.The
invoke_signed()method now correctly supplies all six accounts expected byget_mint_action_instruction_account_metas_cpi_write()in the proper order:
- light_system_program
- mint_signer
- authority
- payer (fee_payer)
- cpi_authority_pda
- cpi_context
This resolves the critical issue flagged in past reviews where only three accounts were provided.
</comment_end>
461-488: LGTM: Helper functions provide clear address derivation utilities.The three helper functions correctly implement address derivation for compressed mints:
derive_compressed_mint_address: Derives from a mint seed via PDAderive_cmint_from_spl_mint: Direct derivation from SPL mint addressfind_spl_mint_address: PDA lookup using the compressed mint seedThe implementations use the appropriate Light Protocol address derivation and Solana PDA functions.
</comment_end>
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
sdk-libs/token-client/src/instructions/create_mint.rs (1)
5-87: Clientcreate_compressed_mint_instructioncorrectly usesCreateCMint; consider avoidingunwrap()on the proofThe refactor to construct a
CreateCMintParamsand then callCreateCMint::new(...).instruction()looks good: you derive the compressed mint address and SPL mint PDA with the same helpers the SDK exposes, and you threaddecimals,mint_authority,freeze_authority, andextensionsthrough cleanly.One thing to double‑check is the use of:
proof: rpc_result.proof.0.unwrap(),If
get_validity_proofever returns a result where the inner proof isNone(e.g., indexer lag, misconfiguration, or an unexpected RPC edge case), this will panic the client instead of returning anRpcError. To keep the API’s failure mode consistent, you could convert this into an error rather than a panic, for example:- let params = CreateCMintParams { - decimals, - address_merkle_tree_root_index, - mint_authority, - proof: rpc_result.proof.0.unwrap(), + let proof = rpc_result + .proof + .0 + .ok_or_else(|| RpcError::CustomError("missing validity proof for compressed mint".into()))?; + + let params = CreateCMintParams { + decimals, + address_merkle_tree_root_index, + mint_authority, + proof, compression_address: compressed_mint_address, mint: find_spl_mint_address(&mint_seed.pubkey()).0, freeze_authority, extensions, };If the invariant really is “proof is always present,” using
expect("...")with a clear message would still be preferable to a bareunwrap()for debugging.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (4)
sdk-tests/csdk-anchor-derived-test/src/lib.rsis excluded by none and included by nonesdk-tests/csdk-anchor-full-derived-test/src/lib.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/src/create_cmint.rsis excluded by none and included by nonesdk-tests/sdk-ctoken-test/tests/shared.rsis excluded by none and included by none
📒 Files selected for processing (6)
sdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs(1 hunks)sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs(7 hunks)sdk-libs/compressed-token-sdk/src/error.rs(2 hunks)sdk-libs/compressed-token-sdk/src/lib.rs(1 hunks)sdk-libs/token-client/src/instructions/create_mint.rs(2 hunks)
🧰 Additional context used
🧠 Learnings (7)
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/decompress_context.rs : DecompressContext implementation should generate account accessor methods, implement PDA/token separation logic, and delegate token processing
Applied to files:
sdk-libs/compressed-token-sdk/src/lib.rssdk-libs/token-client/src/instructions/create_mint.rssdk-libs/compressed-token-sdk/src/error.rssdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rssdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rssdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/*.rs : Module structure in Rust should follow the documented organization: mod.rs for module declarations, traits.rs for core trait implementations (HasCompressionInfo, CompressAs, Compressible), pack_unpack.rs for Pubkey compression and Pack/Unpack traits, variant_enum.rs for account variant enums, instructions.rs for instruction handlers, seed_providers.rs for PDA seed derivation, and decompress_context.rs for decompression trait implementations
Applied to files:
sdk-libs/compressed-token-sdk/src/lib.rssdk-libs/token-client/src/instructions/create_mint.rssdk-libs/compressed-token-sdk/src/error.rssdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rssdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rssdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/pack_unpack.rs : Pack/Unpack trait implementations should compress Pubkey fields by converting them to u8 indices in generated PackedXxx structs for serialization efficiency
Applied to files:
sdk-libs/compressed-token-sdk/src/lib.rssdk-libs/compressed-token-sdk/src/error.rssdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rssdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/variant_enum.rs : CompressedAccountVariant enum generation should implement all required traits: Default, DataHasher, Size, Pack, and Unpack, along with a CompressedAccountData wrapper struct
Applied to files:
sdk-libs/compressed-token-sdk/src/lib.rssdk-libs/compressed-token-sdk/src/error.rssdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rssdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/instructions.rs : Compress instruction handler should be PDA-only, with ctokens compressed via registry; Decompress instruction handler should support full PDA + ctoken support
Applied to files:
sdk-libs/compressed-token-sdk/src/lib.rssdk-libs/token-client/src/instructions/create_mint.rssdk-libs/compressed-token-sdk/src/error.rssdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rssdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/traits.rs : HasCompressionInfo trait should provide CompressionInfo field access; CompressAs trait should provide field-level compression control; Compressible trait should bundle Size + HasCompressionInfo + CompressAs
Applied to files:
sdk-libs/compressed-token-sdk/src/lib.rssdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rs
📚 Learning: 2025-11-24T15:38:31.443Z
Learnt from: CR
Repo: Lightprotocol/light-protocol PR: 0
File: sdk-libs/macros/src/compressible/README.md:0-0
Timestamp: 2025-11-24T15:38:31.443Z
Learning: Applies to sdk-libs/macros/src/compressible/**/seed_providers.rs : Seed providers should implement PDA seed provider functionality with CToken seed provider supporting both account and authority derivation, along with client-side seed functions for off-chain use
Applied to files:
sdk-libs/compressed-token-sdk/src/lib.rssdk-libs/compressed-token-sdk/src/error.rssdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rssdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rssdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs
🧬 Code graph analysis (3)
sdk-libs/token-client/src/instructions/create_mint.rs (1)
sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (5)
derive_compressed_mint_address(447-456)find_spl_mint_address(468-473)new(49-65)new(147-166)new(192-204)
sdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rs (3)
sdk-libs/compressed-token-sdk/src/ctoken/compressible.rs (1)
compress_to_pubkey(41-44)prover/client/src/helpers.rs (1)
b(35-35)sdk-libs/sdk/src/compressible/decompress_runtime.rs (4)
compressible(204-204)fee_payer(65-65)ctoken_config(71-71)ctoken_rent_sponsor(68-68)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (1)
sdk-libs/compressed-token-sdk/src/ctoken/transfer_ctoken.rs (2)
invoke(27-31)invoke_signed(33-37)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Test program-libs-slow
- GitHub Check: Test batched-merkle-tree-simulate
- GitHub Check: Test program-libs-fast
- GitHub Check: programs (system-cpi-test, ["cargo-test-sbf -p system-cpi-test", "cargo test -p light-system-prog...
- GitHub Check: programs (system-cpi-test-v2-functional-read-only, ["cargo-test-sbf -p system-cpi-v2-test -- func...
- GitHub Check: programs (compressed-token-and-e2e, ["cargo-test-sbf -p compressed-token-test --test v1", "cargo-...
- GitHub Check: programs (system-cpi-test-v2-functional-account-infos, ["cargo-test-sbf -p system-cpi-v2-test -- ...
- GitHub Check: programs (account-compression-and-registry, ["cargo-test-sbf -p account-compression-test", "cargo...
- GitHub Check: Forester e2e test
🔇 Additional comments (7)
sdk-libs/compressed-token-sdk/src/lib.rs (1)
16-16: LGTM—verification confirms the re-export is actively used and correctly justified.The
light_compressed_accountdependency exists inCargo.toml, andCompressedProofis actively used by the new instruction builders (confirmed increate_cmint.rswhere it's imported at line 2 and used as a field type at line 30). This re-export appropriately consolidates the public API, allowing downstream consumers to access the type directly through the compressed-token-sdk without coupling to internal light_compressed_account paths.sdk-libs/compressed-token-sdk/src/ctoken/transfer_interface.rs (2)
30-54: Clean refactoring of constructor.The addition of
amountas a direct parameter and initialization ofspl_interfacetoNoneprovides a clear separation between basic transfer setup and optional SPL bridge configuration.
93-111: Error handling now correctly aligned.The previous review flagged mismatches between documented and actual error variants. This has been properly addressed:
- Lines 109–111 now correctly return
SplInterfaceRequiredwhen the SPL interface is missing for SPL<->ctoken transfers- Lines 95, 97 now correctly map
is_ctoken_accounterrors toCannotDetermineAccountTypeThe documentation (lines 89–92) and implementation are now consistent.
Based on past review comments.
sdk-libs/compressed-token-sdk/src/compressible/decompress_runtime.rs (2)
153-153: Verify hardcoded pre_pay_num_epochs value.The
pre_pay_num_epochsis hardcoded to2. This determines how many epochs of rent are prepaid when creating the decompressed token account.Ensure this value is appropriate for all decompression scenarios, or consider making it configurable if different contexts require different prepayment strategies.
124-139: The bump extraction is architecturally guaranteed by the macro system—no fix required.Your concern was well-intentioned, but verification shows the seed structure is not just an assumed pattern; it's enforced by the code generator. Every implementation of
CTokenSeedProviderinsdk-libs/macros/src/compressible/seed_providers.rsfollows the identical pattern:find_program_address()→ extend the seed vector →seeds_vec.push(vec![bump])as the final element. This happens across lines 177–181, 319–323, 391–396, 425–427, 464–466, and 478–481. The extraction logic at lines 124–139 correctly reverses this guaranteed structure using.last().and_then(|b| b.first().copied()), with safeNonehandling for edge cases.There's no risk of alternative seed structures—the macro enforces consistency across all implementations. The code is correct and safe as written.
Optional enhancements worth considering:
- Add a comment documenting that bump is appended by the seed provider macros (helps future maintainers)
- Cross-validate derived PDAs in debug builds for extra confidence, though it's not necessary
sdk-libs/compressed-token-sdk/src/error.rs (1)
52-126: SPL interface error variants and codes are now coherentThe renamed variants (
IncompleteSplInterface,SplInterfaceRequired, and the newMissing*cases) have matching, clear error messages and distinct u32 codes (17020–17028). The mapping covers every concrete variant exactly once before delegating to wrapped errors, so the public error surface is consistent and unambiguous.sdk-libs/compressed-token-sdk/src/ctoken/create_cmint.rs (1)
388-473: CPI‑write AccountInfos ordering and address helpers are consistent
CreateCompressedMintCpiWriteInfos::invoke_signednow passes exactly the sixAccountInfos documented in the comment (light system program, mint signer, authority, fee payer, CPI authority PDA, CPI context), in the same order thatMintActionMetaConfigCpiWriteis expected to emit metas for. That aligns the client‑side slice with the meta layout and avoids the missing‑account / account‑mismatch issues that can easily plague CPI helpers.The helper functions for deriving the compressed mint address and SPL mint PDA (
derive_compressed_mint_address,derive_cmint_from_spl_mint,find_spl_mint_address) consistently useCOMPRESSED_MINT_SEEDandCOMPRESSED_TOKEN_PROGRAM_ID, so address derivations should remain stable and predictable.
Add CToken sdk instructions
sdk-tests/sdk-ctoken-testSummary by CodeRabbit
New Features
Improvements
Refactor
✏️ Tip: You can customize this high-level summary in your review settings.