Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit 394c930

Browse files
[token-2022, confidential-extension] Add confidential transfer authority type (#4025)
1 parent 49c7e7d commit 394c930

File tree

7 files changed

+97
-79
lines changed

7 files changed

+97
-79
lines changed

token/cli/src/main.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,7 @@ async fn command_authorize(
753753
AuthorityType::WithheldWithdraw => "withdraw withheld authority",
754754
AuthorityType::InterestRate => "interest rate authority",
755755
AuthorityType::PermanentDelegate => "permanent delegate",
756+
AuthorityType::ConfidentialTransferMint => "confidential transfer mint authority",
756757
};
757758

758759
let (mint_pubkey, previous_authority) = if !config.sign_only {
@@ -800,6 +801,7 @@ async fn command_authorize(
800801
))
801802
}
802803
}
804+
AuthorityType::ConfidentialTransferMint => unimplemented!(),
803805
}?;
804806

805807
Ok((account, previous_authority))
@@ -833,7 +835,8 @@ async fn command_authorize(
833835
| AuthorityType::TransferFeeConfig
834836
| AuthorityType::WithheldWithdraw
835837
| AuthorityType::InterestRate
836-
| AuthorityType::PermanentDelegate => Err(format!(
838+
| AuthorityType::PermanentDelegate
839+
| AuthorityType::ConfidentialTransferMint => Err(format!(
837840
"Authority type `{}` not supported for SPL Token accounts",
838841
auth_str
839842
)),

token/client/src/token.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,28 +1491,18 @@ where
14911491
pub async fn confidential_transfer_update_mint<S: Signer>(
14921492
&self,
14931493
authority: &S,
1494-
new_authority: Option<&S>,
14951494
auto_approve_new_account: bool,
14961495
auditor_encryption_pubkey: Option<EncryptionPubkey>,
14971496
) -> TokenResult<T::Output> {
1498-
let mut signers = vec![authority];
1499-
let new_authority_pubkey = if let Some(new_authority) = new_authority {
1500-
signers.push(new_authority);
1501-
Some(new_authority.pubkey())
1502-
} else {
1503-
None
1504-
};
1505-
15061497
self.process_ixs(
15071498
&[confidential_transfer::instruction::update_mint(
15081499
&self.program_id,
15091500
&self.pubkey,
15101501
&authority.pubkey(),
1511-
new_authority_pubkey.as_ref(),
15121502
auto_approve_new_account,
15131503
auditor_encryption_pubkey,
15141504
)?],
1515-
&signers,
1505+
&[authority],
15161506
)
15171507
.await
15181508
}

token/program-2022-test/tests/confidential_transfer.rs

Lines changed: 63 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use {
1717
},
1818
BaseStateWithExtensions, ExtensionType,
1919
},
20+
instruction,
2021
pod::EncryptionPubkey,
2122
solana_zk_token_sdk::{
2223
encryption::{auth_encryption::*, elgamal::*},
@@ -287,8 +288,6 @@ async fn check_withheld_amount_in_mint<T>(
287288

288289
#[tokio::test]
289290
async fn ct_initialize_and_update_mint() {
290-
let wrong_keypair = Keypair::new();
291-
292291
let ConfidentialTransferMintWithKeypairs {
293292
ct_mint,
294293
ct_mint_authority,
@@ -317,87 +316,102 @@ async fn ct_initialize_and_update_mint() {
317316

318317
// Change the authority
319318
let new_ct_mint_authority = Keypair::new();
320-
let new_ct_mint = ConfidentialTransferMint {
321-
authority: Some(new_ct_mint_authority.pubkey()).try_into().unwrap(),
322-
..ConfidentialTransferMint::default()
323-
};
319+
let wrong_keypair = Keypair::new();
324320

325321
let err = token
326-
.confidential_transfer_update_mint(
327-
&wrong_keypair,
328-
Some(&new_ct_mint_authority),
329-
new_ct_mint.auto_approve_new_accounts.into(),
330-
new_ct_mint
331-
.withdraw_withheld_authority_encryption_pubkey
332-
.into(),
322+
.set_authority(
323+
token.get_address(),
324+
&wrong_keypair.pubkey(),
325+
Some(&new_ct_mint_authority.pubkey()),
326+
instruction::AuthorityType::ConfidentialTransferMint,
327+
&[&wrong_keypair],
333328
)
334329
.await
335330
.unwrap_err();
331+
336332
assert_eq!(
337333
err,
338334
TokenClientError::Client(Box::new(TransportError::TransactionError(
339-
TransactionError::InstructionError(0, InstructionError::MissingRequiredSignature)
335+
TransactionError::InstructionError(
336+
0,
337+
InstructionError::Custom(TokenError::OwnerMismatch as u32)
338+
)
340339
)))
341340
);
341+
342342
token
343+
.set_authority(
344+
token.get_address(),
345+
&ct_mint_authority.pubkey(),
346+
Some(&new_ct_mint_authority.pubkey()),
347+
instruction::AuthorityType::ConfidentialTransferMint,
348+
&[&ct_mint_authority],
349+
)
350+
.await
351+
.unwrap();
352+
353+
// New authority can change mint parameters while the old cannot
354+
let new_auto_approve_new_accounts = false;
355+
let new_auditor_encryption_pubkey = None;
356+
357+
let err = token
343358
.confidential_transfer_update_mint(
344359
&ct_mint_authority,
345-
Some(&new_ct_mint_authority),
346-
new_ct_mint.auto_approve_new_accounts.into(),
347-
new_ct_mint
348-
.withdraw_withheld_authority_encryption_pubkey
349-
.into(),
360+
new_auto_approve_new_accounts,
361+
new_auditor_encryption_pubkey,
350362
)
351363
.await
352-
.unwrap();
364+
.unwrap_err();
353365

354-
let state = token.get_mint_info().await.unwrap();
355-
let extension = state.get_extension::<ConfidentialTransferMint>().unwrap();
356-
assert_eq!(extension.authority, new_ct_mint.authority);
357366
assert_eq!(
358-
extension.auto_approve_new_accounts,
359-
new_ct_mint.auto_approve_new_accounts
360-
);
361-
assert_eq!(
362-
extension.auditor_encryption_pubkey,
363-
new_ct_mint.auditor_encryption_pubkey
364-
);
365-
assert_eq!(
366-
extension.withdraw_withheld_authority_encryption_pubkey,
367-
ct_mint.withdraw_withheld_authority_encryption_pubkey,
367+
err,
368+
TokenClientError::Client(Box::new(TransportError::TransactionError(
369+
TransactionError::InstructionError(
370+
0,
371+
InstructionError::Custom(TokenError::OwnerMismatch as u32)
372+
)
373+
)))
368374
);
369-
assert_eq!(extension.withheld_amount, ct_mint.withheld_amount);
370375

371-
// Clear the authority
372-
let new_ct_mint = ConfidentialTransferMint::default();
373376
token
374377
.confidential_transfer_update_mint(
375378
&new_ct_mint_authority,
376-
None,
377-
new_ct_mint.auto_approve_new_accounts.into(),
378-
new_ct_mint
379-
.withdraw_withheld_authority_encryption_pubkey
380-
.into(),
379+
new_auto_approve_new_accounts,
380+
new_auditor_encryption_pubkey,
381381
)
382382
.await
383383
.unwrap();
384384

385385
let state = token.get_mint_info().await.unwrap();
386386
let extension = state.get_extension::<ConfidentialTransferMint>().unwrap();
387-
assert_eq!(extension.authority, new_ct_mint.authority);
388387
assert_eq!(
389-
extension.auto_approve_new_accounts,
390-
new_ct_mint.auto_approve_new_accounts
388+
extension.authority,
389+
Some(new_ct_mint_authority.pubkey()).try_into().unwrap()
391390
);
392391
assert_eq!(
393-
extension.auditor_encryption_pubkey,
394-
new_ct_mint.auditor_encryption_pubkey
392+
extension.auto_approve_new_accounts,
393+
new_auto_approve_new_accounts.try_into().unwrap(),
395394
);
396395
assert_eq!(
397-
extension.withdraw_withheld_authority_encryption_pubkey,
398-
ct_mint.withdraw_withheld_authority_encryption_pubkey,
396+
extension.auditor_encryption_pubkey,
397+
new_auditor_encryption_pubkey.try_into().unwrap(),
399398
);
400-
assert_eq!(extension.withheld_amount, ct_mint.withheld_amount);
399+
400+
// Set new authority to None
401+
token
402+
.set_authority(
403+
token.get_address(),
404+
&new_ct_mint_authority.pubkey(),
405+
None,
406+
instruction::AuthorityType::ConfidentialTransferMint,
407+
&[&new_ct_mint_authority],
408+
)
409+
.await
410+
.unwrap();
411+
412+
let state = token.get_mint_info().await.unwrap();
413+
let extension = state.get_extension::<ConfidentialTransferMint>().unwrap();
414+
assert_eq!(extension.authority, None.try_into().unwrap());
401415
}
402416

403417
#[tokio::test]

token/program-2022/src/extension/confidential_transfer/instruction.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,15 @@ pub enum ConfidentialTransferInstruction {
4646

4747
/// Updates the confidential transfer mint configuration for a mint.
4848
///
49+
/// Use `TokenInstruction::SetAuthority` to update the confidential transfer mint authority.
50+
///
4951
/// The `withdraw_withheld_authority_encryption_pubkey` and `withheld_amount` ciphertext are
5052
/// not updatable.
5153
///
5254
/// Accounts expected by this instruction:
5355
///
5456
/// 0. `[writable]` The SPL Token mint.
5557
/// 1. `[signer]` Confidential transfer mint authority.
56-
/// 2. `[signer]` New confidential transfer mint authority.
5758
///
5859
/// Data expected by this instruction:
5960
/// `UpdateMintData`
@@ -576,21 +577,15 @@ pub fn update_mint(
576577
token_program_id: &Pubkey,
577578
mint: &Pubkey,
578579
authority: &Pubkey,
579-
new_authority: Option<&Pubkey>,
580580
auto_approve_new_accounts: bool,
581581
auditor_encryption_pubkey: Option<EncryptionPubkey>,
582582
) -> Result<Instruction, ProgramError> {
583583
check_program_account(token_program_id)?;
584584

585-
let mut accounts = vec![
585+
let accounts = vec![
586586
AccountMeta::new(*mint, false),
587587
AccountMeta::new_readonly(*authority, true),
588588
];
589-
if let Some(new_authority) = new_authority {
590-
accounts.push(AccountMeta::new_readonly(*new_authority, true));
591-
} else {
592-
accounts.push(AccountMeta::new_readonly(Pubkey::default(), false));
593-
}
594589

595590
Ok(encode_instruction(
596591
token_program_id,

token/program-2022/src/extension/confidential_transfer/processor.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ fn process_update_mint(
8787
let account_info_iter = &mut accounts.iter();
8888
let mint_info = next_account_info(account_info_iter)?;
8989
let authority_info = next_account_info(account_info_iter)?;
90-
let new_authority_info = next_account_info(account_info_iter)?;
9190

9291
check_program_account(mint_info.owner)?;
9392
let mint_data = &mut mint_info.data.borrow_mut();
@@ -98,18 +97,14 @@ fn process_update_mint(
9897
let confidential_transfer_mint_authority =
9998
maybe_confidential_transfer_mint_authority.ok_or(TokenError::NoAuthorityExists)?;
10099

101-
if !authority_info.is_signer
102-
|| confidential_transfer_mint_authority != *authority_info.key
103-
|| (!new_authority_info.is_signer && *new_authority_info.key != Pubkey::default())
104-
{
100+
if !authority_info.is_signer {
105101
return Err(ProgramError::MissingRequiredSignature);
106102
}
107103

108-
if *new_authority_info.key == Pubkey::default() {
109-
confidential_transfer_mint.authority = None.try_into()?;
110-
} else {
111-
confidential_transfer_mint.authority = Some(*new_authority_info.key).try_into()?;
104+
if confidential_transfer_mint_authority != *authority_info.key {
105+
return Err(TokenError::OwnerMismatch.into());
112106
}
107+
113108
confidential_transfer_mint.auto_approve_new_accounts = auto_approve_new_account;
114109
confidential_transfer_mint.auditor_encryption_pubkey = *auditor_encryption_pubkey;
115110
Ok(())

token/program-2022/src/instruction.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,9 @@ pub enum AuthorityType {
10071007
InterestRate,
10081008
/// Authority to transfer or burn any tokens for a mint
10091009
PermanentDelegate,
1010+
/// Authority to update confidential transfer mint and aprove accounts for confidential
1011+
/// transfers
1012+
ConfidentialTransferMint,
10101013
}
10111014

10121015
impl AuthorityType {
@@ -1021,6 +1024,7 @@ impl AuthorityType {
10211024
AuthorityType::CloseMint => 6,
10221025
AuthorityType::InterestRate => 7,
10231026
AuthorityType::PermanentDelegate => 8,
1027+
AuthorityType::ConfidentialTransferMint => 9,
10241028
}
10251029
}
10261030

@@ -1035,6 +1039,7 @@ impl AuthorityType {
10351039
6 => Ok(AuthorityType::CloseMint),
10361040
7 => Ok(AuthorityType::InterestRate),
10371041
8 => Ok(AuthorityType::PermanentDelegate),
1042+
9 => Ok(AuthorityType::ConfidentialTransferMint),
10381043
_ => Err(TokenError::InvalidInstruction.into()),
10391044
}
10401045
}

token/program-2022/src/processor.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use {
55
check_program_account, cmp_pubkeys,
66
error::TokenError,
77
extension::{
8-
confidential_transfer::{self, ConfidentialTransferAccount},
8+
confidential_transfer::{self, ConfidentialTransferAccount, ConfidentialTransferMint},
99
cpi_guard::{self, in_cpi, CpiGuard},
1010
default_account_state::{self, DefaultAccountState},
1111
immutable_owner::ImmutableOwner,
@@ -741,6 +741,22 @@ impl Processor {
741741
)?;
742742
extension.delegate = new_authority.try_into()?;
743743
}
744+
AuthorityType::ConfidentialTransferMint => {
745+
let extension = mint.get_extension_mut::<ConfidentialTransferMint>()?;
746+
let maybe_confidential_transfer_mint_authority: Option<Pubkey> =
747+
extension.authority.into();
748+
let confidential_transfer_mint_authority =
749+
maybe_confidential_transfer_mint_authority
750+
.ok_or(TokenError::AuthorityTypeNotSupported)?;
751+
Self::validate_owner(
752+
program_id,
753+
&confidential_transfer_mint_authority,
754+
authority_info,
755+
authority_info_data_len,
756+
account_info_iter.as_slice(),
757+
)?;
758+
extension.authority = new_authority.try_into()?;
759+
}
744760
_ => {
745761
return Err(TokenError::AuthorityTypeNotSupported.into());
746762
}

0 commit comments

Comments
 (0)