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

Commit 16384e2

Browse files
add destination confidential account test for withdraw withheld instructions (#3774)
1 parent 1c3af5e commit 16384e2

File tree

1 file changed

+54
-27
lines changed
  • token/program-2022/src/extension/confidential_transfer

1 file changed

+54
-27
lines changed

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

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,38 @@ fn decode_proof_instruction<T: Pod>(
4545
ProofInstruction::decode_data(&instruction.data).ok_or(ProgramError::InvalidInstructionData)
4646
}
4747

48+
/// Checks if a confidential extension is configured to send funds
49+
fn check_source_confidential_account(
50+
source_confidential_transfer_account: &ConfidentialTransferAccount,
51+
) -> ProgramResult {
52+
source_confidential_transfer_account.approved()
53+
}
54+
55+
/// Checks if a confidential extension is configured to receive funds
56+
fn check_destination_confidential_account(
57+
destination_confidential_transfer_account: &ConfidentialTransferAccount,
58+
) -> ProgramResult {
59+
destination_confidential_transfer_account.approved()?;
60+
61+
if !bool::from(&destination_confidential_transfer_account.allow_balance_credits) {
62+
return Err(TokenError::ConfidentialTransferDepositsAndTransfersDisabled.into());
63+
}
64+
65+
let new_destination_pending_balance_credit_counter =
66+
u64::from(destination_confidential_transfer_account.pending_balance_credit_counter)
67+
.checked_add(1)
68+
.ok_or(ProgramError::InvalidInstructionData)?;
69+
if new_destination_pending_balance_credit_counter
70+
> u64::from(
71+
destination_confidential_transfer_account.maximum_pending_balance_credit_counter,
72+
)
73+
{
74+
return Err(TokenError::MaximumPendingBalanceCreditCounterExceeded.into());
75+
}
76+
77+
Ok(())
78+
}
79+
4880
/// Processes an [InitializeMint] instruction.
4981
fn process_initialize_mint(
5082
accounts: &[AccountInfo],
@@ -326,11 +358,7 @@ fn process_deposit(
326358

327359
let mut confidential_transfer_account =
328360
token_account.get_extension_mut::<ConfidentialTransferAccount>()?;
329-
confidential_transfer_account.approved()?;
330-
331-
if !bool::from(&confidential_transfer_account.allow_balance_credits) {
332-
return Err(TokenError::ConfidentialTransferDepositsAndTransfersDisabled.into());
333-
}
361+
check_destination_confidential_account(confidential_transfer_account)?;
334362

335363
// Divide the deposit amount into low 16 and high 48-bit numbers and then add to the
336364
// appropriate pending ciphertexts
@@ -352,12 +380,6 @@ fn process_deposit(
352380
.ok_or(ProgramError::InvalidInstructionData)?)
353381
.into();
354382

355-
if u64::from(confidential_transfer_account.pending_balance_credit_counter)
356-
> u64::from(confidential_transfer_account.maximum_pending_balance_credit_counter)
357-
{
358-
return Err(TokenError::MaximumPendingBalanceCreditCounterExceeded.into());
359-
}
360-
361383
Ok(())
362384
}
363385

@@ -423,6 +445,7 @@ fn process_withdraw(
423445

424446
let mut confidential_transfer_account =
425447
token_account.get_extension_mut::<ConfidentialTransferAccount>()?;
448+
check_source_confidential_account(confidential_transfer_account)?;
426449

427450
if confidential_transfer_account.encryption_pubkey != proof_data.pubkey {
428451
return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into());
@@ -664,7 +687,8 @@ fn process_source_for_transfer(
664687

665688
let mut confidential_transfer_account =
666689
token_account.get_extension_mut::<ConfidentialTransferAccount>()?;
667-
confidential_transfer_account.approved()?;
690+
check_source_confidential_account(confidential_transfer_account)?;
691+
668692
if *source_encryption_pubkey != confidential_transfer_account.encryption_pubkey {
669693
return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into());
670694
}
@@ -713,11 +737,7 @@ fn process_destination_for_transfer(
713737

714738
let mut destination_confidential_transfer_account =
715739
destination_token_account.get_extension_mut::<ConfidentialTransferAccount>()?;
716-
destination_confidential_transfer_account.approved()?;
717-
718-
if !bool::from(&destination_confidential_transfer_account.allow_balance_credits) {
719-
return Err(TokenError::ConfidentialTransferDepositsAndTransfersDisabled.into());
720-
}
740+
check_destination_confidential_account(destination_confidential_transfer_account)?;
721741

722742
if *destination_encryption_pubkey != destination_confidential_transfer_account.encryption_pubkey
723743
{
@@ -741,14 +761,6 @@ fn process_destination_for_transfer(
741761
.checked_add(1)
742762
.ok_or(ProgramError::InvalidInstructionData)?;
743763

744-
if new_destination_pending_balance_credit_counter
745-
> u64::from(
746-
destination_confidential_transfer_account.maximum_pending_balance_credit_counter,
747-
)
748-
{
749-
return Err(TokenError::MaximumPendingBalanceCreditCounterExceeded.into());
750-
}
751-
752764
destination_confidential_transfer_account.pending_balance_lo =
753765
new_destination_pending_balance_lo;
754766
destination_confidential_transfer_account.pending_balance_hi =
@@ -908,6 +920,7 @@ fn process_withdraw_withheld_tokens_from_mint(
908920
let mut destination_account_data = destination_account_info.data.borrow_mut();
909921
let mut destination_account =
910922
StateWithExtensionsMut::<Account>::unpack(&mut destination_account_data)?;
923+
911924
if destination_account.base.mint != *mint_account_info.key {
912925
return Err(TokenError::MintMismatch.into());
913926
}
@@ -916,7 +929,8 @@ fn process_withdraw_withheld_tokens_from_mint(
916929
}
917930
let mut destination_confidential_transfer_account =
918931
destination_account.get_extension_mut::<ConfidentialTransferAccount>()?;
919-
destination_confidential_transfer_account.approved()?;
932+
check_destination_confidential_account(destination_confidential_transfer_account)?;
933+
920934
// verify consistency of proof data
921935
let previous_instruction =
922936
get_instruction_relative(proof_instruction_offset, instructions_sysvar_info)?;
@@ -955,6 +969,12 @@ fn process_withdraw_withheld_tokens_from_mint(
955969

956970
destination_confidential_transfer_account.pending_balance_lo = new_destination_pending_balance;
957971

972+
destination_confidential_transfer_account.pending_balance_credit_counter =
973+
(u64::from(destination_confidential_transfer_account.pending_balance_credit_counter)
974+
.checked_add(1)
975+
.ok_or(ProgramError::InvalidInstructionData)?)
976+
.into();
977+
958978
// fee is now withdrawn, so zero out mint withheld amount
959979
confidential_transfer_mint.withheld_amount = EncryptedWithheldAmount::zeroed();
960980

@@ -1040,7 +1060,8 @@ fn process_withdraw_withheld_tokens_from_accounts(
10401060

10411061
let mut destination_confidential_transfer_account =
10421062
destination_account.get_extension_mut::<ConfidentialTransferAccount>()?;
1043-
destination_confidential_transfer_account.approved()?;
1063+
check_destination_confidential_account(destination_confidential_transfer_account)?;
1064+
10441065
// verify consistency of proof data
10451066
let previous_instruction =
10461067
get_instruction_relative(proof_instruction_offset, instructions_sysvar_info)?;
@@ -1075,6 +1096,12 @@ fn process_withdraw_withheld_tokens_from_accounts(
10751096
)
10761097
.ok_or(ProgramError::InvalidInstructionData)?;
10771098

1099+
destination_confidential_transfer_account.pending_balance_credit_counter =
1100+
(u64::from(destination_confidential_transfer_account.pending_balance_credit_counter)
1101+
.checked_add(1)
1102+
.ok_or(ProgramError::InvalidInstructionData)?)
1103+
.into();
1104+
10781105
destination_confidential_transfer_account.pending_balance_lo = new_destination_pending_balance;
10791106

10801107
Ok(())

0 commit comments

Comments
 (0)