From 9b2f02dfbdd4415f7a4a3aa7d0df0bf88dae7dfd Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Fri, 2 Jan 2026 16:30:35 +0900 Subject: [PATCH] disallow non-transferable and confidential transfer to be initialized without confidential mint burn --- .../tests/confidential_transfer.rs | 31 +++++++++++++++++++ interface/src/extension/mod.rs | 6 ++++ 2 files changed, 37 insertions(+) diff --git a/clients/rust-legacy/tests/confidential_transfer.rs b/clients/rust-legacy/tests/confidential_transfer.rs index 958c300e0..19e28da74 100644 --- a/clients/rust-legacy/tests/confidential_transfer.rs +++ b/clients/rust-legacy/tests/confidential_transfer.rs @@ -3367,6 +3367,37 @@ async fn confidential_transfer_apply_pending_balance_frozen_account() { ); } +#[tokio::test] +async fn fail_initialize_non_transferable_confidential_mint_without_mint_burn() { + let authority = Keypair::new(); + let auto_approve_new_accounts = true; + let auditor_elgamal_keypair = ElGamalKeypair::new_rand(); + let auditor_elgamal_pubkey = (*auditor_elgamal_keypair.pubkey()).into(); + + let mut context = TestContext::new().await; + let err = context + .init_token_with_mint(vec![ + ExtensionInitializationParams::NonTransferable, + ExtensionInitializationParams::ConfidentialTransferMint { + authority: Some(authority.pubkey()), + auto_approve_new_accounts, + auditor_elgamal_pubkey: Some(auditor_elgamal_pubkey), + }, + ]) + .await + .unwrap_err(); + + assert_eq!( + err, + TokenClientError::Client(Box::new(TransportError::TransactionError( + TransactionError::InstructionError( + 3, + InstructionError::Custom(TokenError::InvalidExtensionCombination as u32) + ) + ))) + ); +} + #[cfg(test)] mod unit_tests { diff --git a/interface/src/extension/mod.rs b/interface/src/extension/mod.rs index 232556803..8f13963ab 100644 --- a/interface/src/extension/mod.rs +++ b/interface/src/extension/mod.rs @@ -1328,6 +1328,7 @@ impl ExtensionType { let mut confidential_mint_burn = false; let mut interest_bearing = false; let mut scaled_ui_amount = false; + let mut non_transferable = false; for extension_type in mint_extension_types { match extension_type { @@ -1339,6 +1340,7 @@ impl ExtensionType { ExtensionType::ConfidentialMintBurn => confidential_mint_burn = true, ExtensionType::InterestBearingConfig => interest_bearing = true, ExtensionType::ScaledUiAmount => scaled_ui_amount = true, + ExtensionType::NonTransferable => non_transferable = true, _ => (), } } @@ -1360,6 +1362,10 @@ impl ExtensionType { return Err(TokenError::InvalidExtensionCombination); } + if non_transferable && confidential_transfer_mint && !confidential_mint_burn { + return Err(TokenError::InvalidExtensionCombination); + } + Ok(()) } }