Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/sdk-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ jobs:
cargo test -p light-client
cargo test -p light-sparse-merkle-tree
cargo test -p light-compressed-token-types
cargo test -p light-ctoken-sdk
cargo test -p light-ctoken-sdk --all-features
steps:
- name: Checkout sources
uses: actions/checkout@v4
Expand Down
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions forester-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ light-client = { workspace = true }
light-prover-client = { workspace = true }
light-registry = { workspace = true, features = ["cpi"] }
account-compression = { workspace = true, features = ["cpi"] }
light-ctoken-interface = { workspace = true }

solana-instruction = { workspace = true }
solana-pubkey = { workspace = true }

tokio = { workspace = true }
futures = { workspace = true }
Expand Down
3 changes: 3 additions & 0 deletions forester-utils/src/instructions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ pub mod address_batch_update;
pub mod create_account;

pub use create_account::create_account_instruction;

pub mod claim;
pub mod withdraw_funding_pool;
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use light_ctoken_sdk::{
CTokenAccount2,
},
ctoken::{derive_ctoken_ata, CreateAssociatedTokenAccount},
token_pool::find_token_pool_pda_with_index,
spl_interface::find_spl_interface_pda_with_index,
ValidityProof,
};
use light_program_test::{utils::assert::assert_rpc_error, LightProgramTest, ProgramTestConfig};
Expand Down Expand Up @@ -190,10 +190,10 @@ fn create_spl_compression_inputs(
// Add SPL token program (spl_token::ID is the owner of SPL token accounts)
let _token_program_index = packed_tree_accounts.insert_or_get_read_only(spl_token::ID);

// Derive token pool PDA using SDK function
// Derive SPL interface PDA using SDK function
let pool_index = 0u8;
let (token_pool_pda, bump) = find_token_pool_pda_with_index(&mint, pool_index);
let pool_account_index = packed_tree_accounts.insert_or_get(token_pool_pda);
let (spl_interface_pda, bump) = find_spl_interface_pda_with_index(&mint, pool_index);
let pool_account_index = packed_tree_accounts.insert_or_get(spl_interface_pda);

// Compress from SPL token account
token_account
Expand Down Expand Up @@ -454,7 +454,7 @@ async fn test_spl_compression_invalid_pool_bump() -> Result<(), RpcError> {

// Derive pool with correct seed but wrong bump
let pool_index = 0u8;
let (_, correct_bump) = find_token_pool_pda_with_index(&mint, pool_index);
let (_, correct_bump) = find_spl_interface_pda_with_index(&mint, pool_index);

// Modify the bump in the compression data to an incorrect value
if let Some(compression) = &mut compression_inputs.token_accounts[0].compression {
Expand Down Expand Up @@ -489,7 +489,7 @@ async fn test_spl_compression_invalid_pool_index() -> Result<(), RpcError> {

// Derive pool with index 1 instead of 0
let wrong_pool_index = 1u8;
let (wrong_pool_pda, wrong_bump) = find_token_pool_pda_with_index(&mint, wrong_pool_index);
let (wrong_pool_pda, wrong_bump) = find_spl_interface_pda_with_index(&mint, wrong_pool_index);

// Update the compression data with wrong pool index
if let Some(compression) = &mut compression_inputs.token_accounts[0].compression {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use light_ctoken_sdk::{
},
CTokenAccount2,
},
token_pool::find_token_pool_pda_with_index,
spl_interface::find_spl_interface_pda_with_index,
ValidityProof,
};
use light_program_test::utils::assert::assert_rpc_error;
Expand Down Expand Up @@ -289,7 +289,7 @@ async fn test_failing_ctoken_to_spl_with_compress_and_close() {
// Now transfer back using CompressAndClose instead of regular transfer
println!("Testing reverse transfer with CompressAndClose: ctoken to SPL");

let (token_pool_pda, token_pool_pda_bump) = find_token_pool_pda_with_index(&mint, 0);
let (spl_interface_pda, spl_interface_pda_bump) = find_spl_interface_pda_with_index(&mint, 0);

let transfer_ix = CtokenToSplTransferAndClose {
source_ctoken_account: associated_token_account,
Expand All @@ -298,8 +298,8 @@ async fn test_failing_ctoken_to_spl_with_compress_and_close() {
authority: recipient.pubkey(),
mint,
payer: payer.pubkey(),
token_pool_pda,
token_pool_pda_bump,
spl_interface_pda,
spl_interface_pda_bump,
spl_token_program: anchor_spl::token::ID,
}
.instruction()
Expand All @@ -319,8 +319,8 @@ pub struct CtokenToSplTransferAndClose {
pub authority: Pubkey,
pub mint: Pubkey,
pub payer: Pubkey,
pub token_pool_pda: Pubkey,
pub token_pool_pda_bump: u8,
pub spl_interface_pda: Pubkey,
pub spl_interface_pda_bump: u8,
pub spl_token_program: Pubkey,
}

Expand All @@ -335,8 +335,8 @@ impl CtokenToSplTransferAndClose {
AccountMeta::new(self.destination_spl_token_account, false),
// Authority (index 3) - signer
AccountMeta::new(self.authority, true),
// Token pool PDA (index 4) - writable
AccountMeta::new(self.token_pool_pda, false),
// SPL interface PDA (index 4) - writable
AccountMeta::new(self.spl_interface_pda, false),
// SPL Token program (index 5) - needed for CPI
AccountMeta::new_readonly(self.spl_token_program, false),
];
Expand Down Expand Up @@ -368,7 +368,7 @@ impl CtokenToSplTransferAndClose {
2, // destination SPL token account index
4, // pool_account_index
0, // pool_index (TODO: make dynamic)
self.token_pool_pda_bump,
self.spl_interface_pda_bump,
)),
delegate_is_set: false,
method_used: true,
Expand Down
3 changes: 3 additions & 0 deletions sdk-libs/ctoken-sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ version = "0.1.0"
edition = { workspace = true }

[features]
default = []
v1 = []
compressible = []

anchor = ["anchor-lang", "light-compressed-token-types/anchor", "light-ctoken-interface/anchor"]
cpi-context = ["light-sdk/cpi-context"]
Expand Down
5 changes: 4 additions & 1 deletion sdk-libs/ctoken-sdk/src/compressed_token/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
//! Compressed token account types and instruction builders.

#[cfg(feature = "v1")]
mod v1;
mod v2;

pub mod ctoken_instruction;

// Re-export everything from v1 and v2
#[cfg(feature = "v1")]
pub use v1::*;
pub use v2::*;
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use solana_pubkey::Pubkey;
use crate::{
compressed_token::mint_action::MintActionMetaConfig,
error::{Result, TokenSdkError},
TokenPool,
spl_interface::SplInterfacePda,
};

pub const MINT_TO_COMPRESSED_DISCRIMINATOR: u8 = 101;
Expand All @@ -32,7 +32,7 @@ pub struct MintToCompressedInputs {
pub token_account_version: u8,
pub cpi_context_pubkey: Option<Pubkey>,
/// Required if the mint is decompressed
pub token_pool: Option<TokenPool>,
pub spl_interface_pda: Option<SplInterfacePda>,
}

/// Create a mint_to_compressed instruction (wrapper around mint_action)
Expand All @@ -53,7 +53,7 @@ pub fn create_mint_to_compressed_instruction(
proof,
token_account_version,
cpi_context_pubkey,
token_pool: _,
spl_interface_pda: _,
} = inputs;

let mint_to_action =
Expand Down
8 changes: 4 additions & 4 deletions sdk-libs/ctoken-sdk/src/compressible/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pub mod claim;
//! Compressible token utilities for runtime decompression.

#[cfg(feature = "compressible")]
pub mod decompress_runtime;
pub mod withdraw_funding_pool;

pub use claim::*;
#[cfg(feature = "compressible")]
pub use decompress_runtime::{process_decompress_tokens_runtime, CTokenSeedProvider};
pub use withdraw_funding_pool::*;
5 changes: 5 additions & 0 deletions sdk-libs/ctoken-sdk/src/ctoken/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
//! High-level builders for compressed token operations.
//!
//! Provides instruction builders and CPI helpers for creating, transferring,
//! and managing compressed token accounts.

mod close;
mod compressible;
mod create;
Expand Down
22 changes: 11 additions & 11 deletions sdk-libs/ctoken-sdk/src/ctoken/transfer_ctoken_spl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ pub struct TransferCtokenToSpl {
pub authority: Pubkey,
pub mint: Pubkey,
pub payer: Pubkey,
pub token_pool_pda: Pubkey,
pub token_pool_pda_bump: u8,
pub spl_interface_pda: Pubkey,
pub spl_interface_pda_bump: u8,
pub spl_token_program: Pubkey,
}

Expand All @@ -33,8 +33,8 @@ pub struct TransferCtokenToSplAccountInfos<'info> {
pub authority: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
pub payer: AccountInfo<'info>,
pub token_pool_pda: AccountInfo<'info>,
pub token_pool_pda_bump: u8,
pub spl_interface_pda: AccountInfo<'info>,
pub spl_interface_pda_bump: u8,
pub spl_token_program: AccountInfo<'info>,
pub compressed_token_program_authority: AccountInfo<'info>,
}
Expand All @@ -54,7 +54,7 @@ impl<'info> TransferCtokenToSplAccountInfos<'info> {
self.source_ctoken_account, // Index 1: Source ctoken account
self.destination_spl_token_account, // Index 2: Destination SPL token account
self.authority, // Index 3: Authority (signer)
self.token_pool_pda, // Index 4: Token pool PDA
self.spl_interface_pda, // Index 4: SPL interface PDA
self.spl_token_program, // Index 5: SPL Token program
];
invoke(&instruction, &account_infos)
Expand All @@ -70,7 +70,7 @@ impl<'info> TransferCtokenToSplAccountInfos<'info> {
self.source_ctoken_account, // Index 1: Source ctoken account
self.destination_spl_token_account, // Index 2: Destination SPL token account
self.authority, // Index 3: Authority (signer)
self.token_pool_pda, // Index 4: Token pool PDA
self.spl_interface_pda, // Index 4: SPL interface PDA
self.spl_token_program, // Index 5: SPL Token program
];
invoke_signed(&instruction, &account_infos, signer_seeds)
Expand All @@ -86,8 +86,8 @@ impl<'info> From<&TransferCtokenToSplAccountInfos<'info>> for TransferCtokenToSp
authority: *account_infos.authority.key,
mint: *account_infos.mint.key,
payer: *account_infos.payer.key,
token_pool_pda: *account_infos.token_pool_pda.key,
token_pool_pda_bump: account_infos.token_pool_pda_bump,
spl_interface_pda: *account_infos.spl_interface_pda.key,
spl_interface_pda_bump: account_infos.spl_interface_pda_bump,
spl_token_program: *account_infos.spl_token_program.key,
}
}
Expand All @@ -105,8 +105,8 @@ impl TransferCtokenToSpl {
AccountMeta::new(self.destination_spl_token_account, false),
// Authority (index 3) - signer
AccountMeta::new_readonly(self.authority, true),
// Token pool PDA (index 4) - writable
AccountMeta::new(self.token_pool_pda, false),
// SPL interface PDA (index 4) - writable
AccountMeta::new(self.spl_interface_pda, false),
// SPL Token program (index 5) - needed for CPI
AccountMeta::new_readonly(self.spl_token_program, false),
];
Expand Down Expand Up @@ -135,7 +135,7 @@ impl TransferCtokenToSpl {
2, // destination SPL token account index
4, // pool_account_index
0, // pool_index (TODO: make dynamic)
self.token_pool_pda_bump,
self.spl_interface_pda_bump,
)),
delegate_is_set: false,
method_used: true,
Expand Down
36 changes: 18 additions & 18 deletions sdk-libs/ctoken-sdk/src/ctoken/transfer_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use crate::{error::TokenSdkError, utils::is_ctoken_account};
pub struct SplInterface<'info> {
pub mint: AccountInfo<'info>,
pub spl_token_program: AccountInfo<'info>,
pub token_pool_pda: AccountInfo<'info>,
pub token_pool_pda_bump: u8,
pub spl_interface_pda: AccountInfo<'info>,
pub spl_interface_pda_bump: u8,
}
Comment on lines 12 to 17
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Behavior is correct, but error names still reference the old token pool abstraction

The refactor from token pool to SPL interface in this builder looks solid:

  • SplInterface<'info> now carries spl_interface_pda and spl_interface_pda_bump.
  • with_spl_interface enforces presence of mint, SPL token program, SPL interface PDA, and bump before enabling SPL↔ctoken transfers.
  • The invoke / invoke_signed branches correctly plumb spl_interface_pda and its bump into TransferCtokenToSplAccountInfos and TransferSplToCtokenAccountInfos.

One small inconsistency is that with_spl_interface still uses:

TokenSdkError::MissingTokenPoolPda
TokenSdkError::MissingTokenPoolPdaBump

for the SPL interface PDA and bump. Given the rest of the file and the new SplInterfaceRequired error are framed in terms of “SPL interface”, these legacy variant names (and likely their user-facing messages) will be confusing.

If you can afford it in this PR, I’d suggest:

  • renaming those error variants and messages to MissingSplInterfacePda / MissingSplInterfacePdaBump (with a deprecation alias if needed), or
  • at least updating their error strings to talk about “SPL interface PDA” instead of “token pool PDA”.

That keeps the error surface aligned with the new abstraction and makes debugging much clearer.

Also applies to: 56-87, 99-151, 163-221

🤖 Prompt for AI Agents
sdk-libs/ctoken-sdk/src/ctoken/transfer_interface.rs lines 12-17 (also apply
fixes in ranges 56-87, 99-151, 163-221): the builder and error usage still
reference legacy TokenSdkError::MissingTokenPoolPda and
TokenSdkError::MissingTokenPoolPdaBump which are inconsistent with the new
SplInterface abstraction; rename these error variants to MissingSplInterfacePda
and MissingSplInterfacePdaBump (or add deprecated aliases forwarding to the new
names), update all matches/returns/usages and their user-facing error strings to
say “SPL interface PDA” / “SPL interface PDA bump”, and run/adjust any tests or
docs referencing the old names so all error messages and variants consistently
reflect the SPL interface abstraction.


pub struct TransferInterface<'info> {
Expand Down Expand Up @@ -56,32 +56,32 @@ impl<'info> TransferInterface<'info> {
/// # Arguments
/// * `mint` - Optional mint account (required for SPL<->ctoken transfers)
/// * `spl_token_program` - Optional SPL token program (required for SPL<->ctoken transfers)
/// * `compressed_token_pool_pda` - Optional token pool PDA (required for SPL<->ctoken transfers)
/// * `compressed_token_pool_pda_bump` - Optional bump seed for token pool PDA
/// * `spl_interface_pda` - Optional SPL interface PDA (required for SPL<->ctoken transfers)
/// * `spl_interface_pda_bump` - Optional bump seed for SPL interface PDA
pub fn with_spl_interface(
mut self,
mint: Option<AccountInfo<'info>>,
spl_token_program: Option<AccountInfo<'info>>,
token_pool_pda: Option<AccountInfo<'info>>,
token_pool_pda_bump: Option<u8>,
spl_interface_pda: Option<AccountInfo<'info>>,
spl_interface_pda_bump: Option<u8>,
) -> Result<Self, ProgramError> {
let mint =
mint.ok_or_else(|| ProgramError::Custom(TokenSdkError::MissingMintAccount.into()))?;

let spl_token_program = spl_token_program
.ok_or_else(|| ProgramError::Custom(TokenSdkError::MissingSplTokenProgram.into()))?;

let token_pool_pda = token_pool_pda
let spl_interface_pda = spl_interface_pda
.ok_or_else(|| ProgramError::Custom(TokenSdkError::MissingTokenPoolPda.into()))?;

let token_pool_pda_bump = token_pool_pda_bump
let spl_interface_pda_bump = spl_interface_pda_bump
.ok_or_else(|| ProgramError::Custom(TokenSdkError::MissingTokenPoolPdaBump.into()))?;

self.spl_interface = Some(SplInterface {
mint,
spl_token_program,
token_pool_pda,
token_pool_pda_bump,
spl_interface_pda,
spl_interface_pda_bump,
});
Ok(self)
}
Expand Down Expand Up @@ -118,8 +118,8 @@ impl<'info> TransferInterface<'info> {
authority: self.authority.clone(),
mint: config.mint.clone(),
payer: self.payer.clone(),
token_pool_pda: config.token_pool_pda.clone(),
token_pool_pda_bump: config.token_pool_pda_bump,
spl_interface_pda: config.spl_interface_pda.clone(),
spl_interface_pda_bump: config.spl_interface_pda_bump,
spl_token_program: config.spl_token_program.clone(),
compressed_token_program_authority: self
.compressed_token_program_authority
Expand All @@ -140,8 +140,8 @@ impl<'info> TransferInterface<'info> {
authority: self.authority.clone(),
mint: config.mint.clone(),
payer: self.payer.clone(),
token_pool_pda: config.token_pool_pda.clone(),
token_pool_pda_bump: config.token_pool_pda_bump,
spl_interface_pda: config.spl_interface_pda.clone(),
spl_interface_pda_bump: config.spl_interface_pda_bump,
spl_token_program: config.spl_token_program.clone(),
compressed_token_program_authority: self
.compressed_token_program_authority
Expand Down Expand Up @@ -188,8 +188,8 @@ impl<'info> TransferInterface<'info> {
authority: self.authority.clone(),
mint: config.mint.clone(),
payer: self.payer.clone(),
token_pool_pda: config.token_pool_pda.clone(),
token_pool_pda_bump: config.token_pool_pda_bump,
spl_interface_pda: config.spl_interface_pda.clone(),
spl_interface_pda_bump: config.spl_interface_pda_bump,
spl_token_program: config.spl_token_program.clone(),
compressed_token_program_authority: self
.compressed_token_program_authority
Expand All @@ -210,8 +210,8 @@ impl<'info> TransferInterface<'info> {
authority: self.authority.clone(),
mint: config.mint.clone(),
payer: self.payer.clone(),
token_pool_pda: config.token_pool_pda.clone(),
token_pool_pda_bump: config.token_pool_pda_bump,
spl_interface_pda: config.spl_interface_pda.clone(),
spl_interface_pda_bump: config.spl_interface_pda_bump,
spl_token_program: config.spl_token_program.clone(),
compressed_token_program_authority: self
.compressed_token_program_authority
Expand Down
Loading