Skip to content

Commit aad94a4

Browse files
authored
fix: ctoken cpi context (#1870)
* fix: check cpi context account * fix tests
1 parent 5490ea1 commit aad94a4

File tree

6 files changed

+30
-12
lines changed

6 files changed

+30
-12
lines changed

program-tests/system-cpi-test/tests/test.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,7 +1387,7 @@ async fn test_approve_revoke_burn_freeze_thaw_with_cpi_context() {
13871387
.value
13881388
.items[0]
13891389
.clone();
1390-
perform_with_input_accounts(
1390+
let res = perform_with_input_accounts(
13911391
&mut test_indexer,
13921392
&mut rpc,
13931393
&payer,
@@ -1397,20 +1397,16 @@ async fn test_approve_revoke_burn_freeze_thaw_with_cpi_context() {
13971397
u32::MAX,
13981398
WithInputAccountsMode::Burn,
13991399
)
1400-
.await
1400+
.await;
1401+
assert_rpc_error(
1402+
res,
1403+
0,
1404+
light_compressed_token::ErrorCode::CpiContextSetNotUsable.into(),
1405+
)
14011406
.unwrap();
1402-
let compressed_token_data = test_indexer
1403-
.get_compressed_token_accounts_by_owner(&payer.pubkey(), None, None)
1404-
.await
1405-
.unwrap()
1406-
.value
1407-
.items[0]
1408-
.clone();
1409-
let mut ref_data = ref_compressed_token_data.token.clone();
1410-
ref_data.amount = 1;
1411-
assert_eq!(compressed_token_data.token, ref_data);
14121407
}
14131408
}
1409+
14141410
/// Test:
14151411
/// 1. Cannot create an address in a program owned address Merkle tree owned by a different program (InvalidMerkleTreeOwner)
14161412
/// 2. Cannot create a compressed account in a program owned state Merkle tree owned by a different program (InvalidMerkleTreeOwner)

programs/compressed-token/src/burn.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub fn process_burn<'a, 'b, 'c, 'info: 'b + 'c>(
3636
) -> Result<()> {
3737
let inputs: CompressedTokenInstructionDataBurn =
3838
CompressedTokenInstructionDataBurn::deserialize(&mut inputs.as_slice())?;
39+
crate::check_cpi_context(&inputs.cpi_context)?;
3940
burn_spl_from_pool_pda(&ctx, &inputs)?;
4041
let mint = ctx.accounts.mint.key();
4142
let (compressed_input_accounts, output_compressed_accounts) =

programs/compressed-token/src/delegation.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ pub fn process_approve<'a, 'b, 'c, 'info: 'b + 'c>(
4949
) -> Result<()> {
5050
let inputs: CompressedTokenInstructionDataApprove =
5151
CompressedTokenInstructionDataApprove::deserialize(&mut inputs.as_slice())?;
52+
// CPI context check not needed: delegation operations don't modify Solana account state
5253
let (compressed_input_accounts, output_compressed_accounts) =
5354
create_input_and_output_accounts_approve(
5455
&inputs,
@@ -183,6 +184,7 @@ pub fn process_revoke<'a, 'b, 'c, 'info: 'b + 'c>(
183184
) -> Result<()> {
184185
let inputs: CompressedTokenInstructionDataRevoke =
185186
CompressedTokenInstructionDataRevoke::deserialize(&mut inputs.as_slice())?;
187+
// CPI context check not needed: delegation operations don't modify Solana account state
186188
let (compressed_input_accounts, output_compressed_accounts) =
187189
create_input_and_output_accounts_revoke(
188190
&inputs,

programs/compressed-token/src/freeze.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub fn process_freeze_or_thaw<
4242
) -> Result<()> {
4343
let inputs: CompressedTokenInstructionDataFreeze =
4444
CompressedTokenInstructionDataFreeze::deserialize(&mut inputs.as_slice())?;
45+
// CPI context check not needed: freeze/thaw operations don't modify Solana account state
4546
let (compressed_input_accounts, output_compressed_accounts) =
4647
create_input_and_output_accounts_freeze_or_thaw::<FROZEN_INPUTS, FROZEN_OUTPUTS>(
4748
&inputs,

programs/compressed-token/src/lib.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ pub mod light_compressed_token {
148148
inputs.extend_from_slice(&[0u8; 1]);
149149
let inputs: CompressedTokenInstructionDataTransfer =
150150
CompressedTokenInstructionDataTransfer::deserialize(&mut inputs.as_slice())?;
151+
// Only check CPI context if we're compressing or decompressing (modifying Solana account state)
152+
if inputs.compress_or_decompress_amount.is_some() {
153+
check_cpi_context(&inputs.cpi_context)?;
154+
}
151155
process_transfer::process_transfer(ctx, inputs)
152156
}
153157

@@ -276,4 +280,17 @@ pub enum ErrorCode {
276280
NoMatchingBumpFound,
277281
NoAmount,
278282
AmountsAndAmountProvided,
283+
#[msg("Cpi context set and set first is not usable with burn, compression(transfer ix) or decompress(transfer).")]
284+
CpiContextSetNotUsable,
285+
}
286+
287+
/// Checks if CPI context usage is valid for the current instruction
288+
/// Throws an error if cpi_context is Some and (set_context OR first_set_context is true)
289+
fn check_cpi_context(cpi_context: &Option<CompressedCpiContext>) -> Result<()> {
290+
if let Some(ctx) = cpi_context {
291+
if ctx.set_context || ctx.first_set_context {
292+
return Err(ErrorCode::CpiContextSetNotUsable.into());
293+
}
294+
}
295+
Ok(())
279296
}

programs/compressed-token/src/process_compress_spl_token_account.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub fn process_compress_spl_token_account<'info>(
1515
remaining_amount: Option<u64>,
1616
cpi_context: Option<CompressedCpiContext>,
1717
) -> Result<()> {
18+
crate::check_cpi_context(&cpi_context)?;
1819
let compression_token_account =
1920
if let Some(token_account) = ctx.accounts.compress_or_decompress_token_account.as_ref() {
2021
token_account

0 commit comments

Comments
 (0)