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

Commit 5da184a

Browse files
token-2022: [OS-SPL-ADV-00] Enable and fix account ordering on confidential transfer with split proofs (#5931)
* enable auto cloase of context accounts * add auto-close on test * fix account order on transfer with proof contexts * add test to make sure that the context accounts are cleared * add test to verify lamport destination
1 parent 71e9818 commit 5da184a

File tree

4 files changed

+101
-27
lines changed

4 files changed

+101
-27
lines changed

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

Lines changed: 85 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ use {
2020
self,
2121
account_info::TransferAccountInfo,
2222
instruction::{
23-
TransferSplitContextStateAccounts, TransferWithFeeSplitContextStateAccounts,
23+
CloseSplitContextStateAccounts, TransferSplitContextStateAccounts,
24+
TransferWithFeeSplitContextStateAccounts,
2425
},
2526
ConfidentialTransferAccount, MAXIMUM_DEPOSIT_TRANSFER_AMOUNT,
2627
},
@@ -2668,21 +2669,33 @@ async fn confidential_transfer_transfer_with_split_proof_contexts_in_parallel()
26682669
let ciphertext_validity_proof_context_state_account = Keypair::new();
26692670
let range_proof_context_state_account = Keypair::new();
26702671

2672+
let lamport_destination = Pubkey::new_unique();
2673+
2674+
let close_split_context_state_accounts = CloseSplitContextStateAccounts {
2675+
lamport_destination: &lamport_destination,
2676+
zk_token_proof_program: &zk_token_proof_program::id(),
2677+
};
2678+
26712679
let transfer_context_state_accounts = TransferSplitContextStateAccounts {
26722680
equality_proof: &equality_proof_context_state_account.pubkey(),
26732681
ciphertext_validity_proof: &ciphertext_validity_proof_context_state_account.pubkey(),
26742682
range_proof: &range_proof_context_state_account.pubkey(),
26752683
authority: &context_state_authority.pubkey(),
26762684
no_op_on_uninitialized_split_context_state: true,
2677-
close_split_context_state_accounts: None,
2685+
close_split_context_state_accounts: Some(close_split_context_state_accounts),
26782686
};
26792687

26802688
let equality_and_ciphertext_proof_signers = vec![
26812689
&alice,
26822690
&equality_proof_context_state_account,
26832691
&ciphertext_validity_proof_context_state_account,
2692+
&context_state_authority,
2693+
];
2694+
let range_proof_signers = vec![
2695+
&alice,
2696+
&range_proof_context_state_account,
2697+
&context_state_authority,
26842698
];
2685-
let range_proof_signers = vec![&alice, &range_proof_context_state_account];
26862699
token
26872700
.confidential_transfer_transfer_with_split_proofs_in_parallel(
26882701
&alice_meta.token_account,
@@ -2724,6 +2737,27 @@ async fn confidential_transfer_transfer_with_split_proof_contexts_in_parallel()
27242737
},
27252738
)
27262739
.await;
2740+
2741+
let error = token
2742+
.get_account(equality_proof_context_state_account.pubkey())
2743+
.await
2744+
.unwrap_err();
2745+
assert_eq!(error, TokenClientError::AccountNotFound);
2746+
2747+
let error = token
2748+
.get_account(ciphertext_validity_proof_context_state_account.pubkey())
2749+
.await
2750+
.unwrap_err();
2751+
assert_eq!(error, TokenClientError::AccountNotFound);
2752+
2753+
let error = token
2754+
.get_account(range_proof_context_state_account.pubkey())
2755+
.await
2756+
.unwrap_err();
2757+
assert_eq!(error, TokenClientError::AccountNotFound);
2758+
2759+
let lamport_destination = token.get_account(lamport_destination).await.unwrap();
2760+
assert!(lamport_destination.lamports > 0);
27272761
}
27282762

27292763
#[tokio::test]
@@ -3043,6 +3077,13 @@ async fn confidential_transfer_transfer_with_fee_and_split_proof_context_in_para
30433077
let fee_ciphertext_validity_proof_context_state_account = Keypair::new();
30443078
let range_proof_context_state_account = Keypair::new();
30453079

3080+
let lamport_destination = Pubkey::new_unique();
3081+
3082+
let close_split_context_state_accounts = CloseSplitContextStateAccounts {
3083+
lamport_destination: &lamport_destination,
3084+
zk_token_proof_program: &zk_token_proof_program::id(),
3085+
};
3086+
30463087
let transfer_context_state_accounts = TransferWithFeeSplitContextStateAccounts {
30473088
equality_proof: &equality_proof_context_state_account.pubkey(),
30483089
transfer_amount_ciphertext_validity_proof:
@@ -3053,20 +3094,26 @@ async fn confidential_transfer_transfer_with_fee_and_split_proof_context_in_para
30533094
range_proof: &range_proof_context_state_account.pubkey(),
30543095
authority: &context_state_authority.pubkey(),
30553096
no_op_on_uninitialized_split_context_state: true,
3056-
close_split_context_state_accounts: None,
3097+
close_split_context_state_accounts: Some(close_split_context_state_accounts),
30573098
};
30583099

30593100
let equality_and_ciphertext_proof_signers = vec![
30603101
&alice,
30613102
&equality_proof_context_state_account,
30623103
&transfer_amount_ciphertext_validity_proof_context_state_account,
3104+
&context_state_authority,
30633105
];
30643106
let fee_sigma_proof_signers = vec![
30653107
&alice,
30663108
&fee_sigma_proof_context_state_account,
30673109
&fee_ciphertext_validity_proof_context_state_account,
3110+
&context_state_authority,
3111+
];
3112+
let range_proof_signers = vec![
3113+
&alice,
3114+
&range_proof_context_state_account,
3115+
&context_state_authority,
30683116
];
3069-
let range_proof_signers = vec![&alice, &range_proof_context_state_account];
30703117
token
30713118
.confidential_transfer_transfer_with_fee_and_split_proofs_in_parallel(
30723119
&alice_meta.token_account,
@@ -3113,4 +3160,37 @@ async fn confidential_transfer_transfer_with_fee_and_split_proof_context_in_para
31133160
},
31143161
)
31153162
.await;
3163+
3164+
let error = token
3165+
.get_account(equality_proof_context_state_account.pubkey())
3166+
.await
3167+
.unwrap_err();
3168+
assert_eq!(error, TokenClientError::AccountNotFound);
3169+
3170+
let error = token
3171+
.get_account(transfer_amount_ciphertext_validity_proof_context_state_account.pubkey())
3172+
.await
3173+
.unwrap_err();
3174+
assert_eq!(error, TokenClientError::AccountNotFound);
3175+
3176+
let error = token
3177+
.get_account(fee_sigma_proof_context_state_account.pubkey())
3178+
.await
3179+
.unwrap_err();
3180+
assert_eq!(error, TokenClientError::AccountNotFound);
3181+
3182+
let error = token
3183+
.get_account(fee_ciphertext_validity_proof_context_state_account.pubkey())
3184+
.await
3185+
.unwrap_err();
3186+
assert_eq!(error, TokenClientError::AccountNotFound);
3187+
3188+
let error = token
3189+
.get_account(range_proof_context_state_account.pubkey())
3190+
.await
3191+
.unwrap_err();
3192+
assert_eq!(error, TokenClientError::AccountNotFound);
3193+
3194+
let lamport_destination = token.get_account(lamport_destination).await.unwrap();
3195+
assert!(lamport_destination.lamports > 0);
31163196
}

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

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -399,14 +399,14 @@ pub enum ConfidentialTransferInstruction {
399399
/// 5. `[]` Context state account for
400400
/// `VerifyBatchedGroupedCiphertext2HandlesValidityProof`.
401401
/// 6. `[]` Context state account for `VerifyBatchedRangeProofU128`.
402-
/// 7. `[signer]` The source account owner.
403402
/// If `close_split_context_state_on_execution` is set, all context state
404-
/// accounts must be `writable` and the following additional sequence
405-
/// of accounts are needed:
406-
/// 8. `[]` The destination account for lamports from the context state
403+
/// accounts must be `writable` and the following sequence
404+
/// of accounts that are marked with asterisk are needed:
405+
/// 7*. `[]` The destination account for lamports from the context state
407406
/// accounts.
408-
/// 9. `[signer]` The context state account owner.
409-
/// 10. `[]` The zk token proof program.
407+
/// 8*. `[signer]` The context state account owner.
408+
/// 9*. `[]` The zk token proof program.
409+
/// 10. `[signer]` The source account owner.
410410
///
411411
/// * Transfer with fee
412412
/// 1. `[writable]` The source SPL Token account.
@@ -420,14 +420,14 @@ pub enum ConfidentialTransferInstruction {
420420
/// 7. `[]` Context state account for
421421
/// `VerifyBatchedGroupedCiphertext2HandlesValidityProof`.
422422
/// 8. `[]` Context state account for `VerifyBatchedRangeProofU256`.
423-
/// 9. `[signer]` The source account owner.
424423
/// If `close_split_context_state_on_execution` is set, all context state
425-
/// accounts must be `writable` and the following additional sequence
426-
/// of accounts are needed:
427-
/// 10. `[]` The destination account for lamports from the context state
424+
/// accounts must be `writable` and the following sequence
425+
/// of accounts that are marked with asterisk are needed:
426+
/// 9*. `[]` The destination account for lamports from the context state
428427
/// accounts.
429-
/// 11. `[signer]` The context state account owner.
430-
/// 12. `[]` The zk token proof program.
428+
/// 10*. `[signer]` The context state account owner.
429+
/// 11*. `[]` The zk token proof program.
430+
/// 12. `[signer]` The source account owner.
431431
///
432432
/// Data expected by this instruction:
433433
/// `TransferWithSplitProofsInstructionData`
@@ -1389,7 +1389,6 @@ pub fn transfer_with_split_proofs(
13891389
false,
13901390
));
13911391
accounts.push(AccountMeta::new(*context_accounts.range_proof, false));
1392-
accounts.push(AccountMeta::new_readonly(*source_account_authority, true));
13931392
accounts.push(AccountMeta::new(
13941393
*close_split_context_state_on_execution_accounts.lamport_destination,
13951394
false,
@@ -1399,6 +1398,7 @@ pub fn transfer_with_split_proofs(
13991398
*close_split_context_state_on_execution_accounts.zk_token_proof_program,
14001399
false,
14011400
));
1401+
accounts.push(AccountMeta::new_readonly(*source_account_authority, true));
14021402
true
14031403
} else {
14041404
// If `close_split_context_state_accounts` is not set, then context state
@@ -1473,7 +1473,6 @@ pub fn transfer_with_fee_and_split_proofs(
14731473
false,
14741474
));
14751475
accounts.push(AccountMeta::new(*context_accounts.range_proof, false));
1476-
accounts.push(AccountMeta::new_readonly(*source_account_authority, true));
14771476
accounts.push(AccountMeta::new(
14781477
*close_split_context_state_on_execution_accounts.lamport_destination,
14791478
false,
@@ -1483,6 +1482,7 @@ pub fn transfer_with_fee_and_split_proofs(
14831482
*close_split_context_state_on_execution_accounts.zk_token_proof_program,
14841483
false,
14851484
));
1485+
accounts.push(AccountMeta::new_readonly(*source_account_authority, true));
14861486
true
14871487
} else {
14881488
// If `close_split_context_state_accounts` is not set, then context state
@@ -1508,7 +1508,6 @@ pub fn transfer_with_fee_and_split_proofs(
15081508
false,
15091509
));
15101510
accounts.push(AccountMeta::new_readonly(*source_account_authority, true));
1511-
15121511
false
15131512
};
15141513

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

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,13 +1164,6 @@ pub(crate) fn process_instruction(
11641164
{
11651165
let data =
11661166
decode_instruction_data::<TransferWithSplitProofsInstructionData>(input)?;
1167-
1168-
// Remove this error on the next Solana version upgrade.
1169-
if data.close_split_context_state_on_execution.into() {
1170-
msg!("Auto-close of context state account is not yet supported");
1171-
return Err(ProgramError::InvalidInstructionData);
1172-
}
1173-
11741167
process_transfer(
11751168
program_id,
11761169
accounts,

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ pub fn verify_transfer_proof(
188188
if close_split_context_state_on_execution {
189189
let lamport_destination_account_info = next_account_info(account_info_iter)?;
190190
let context_state_account_authority_info = next_account_info(account_info_iter)?;
191+
let _zk_token_proof_program = next_account_info(account_info_iter)?;
191192

192193
msg!("Closing equality proof context state account");
193194
invoke(
@@ -363,6 +364,7 @@ pub fn verify_transfer_with_fee_proof(
363364
if close_split_context_state_on_execution {
364365
let lamport_destination_account_info = next_account_info(account_info_iter)?;
365366
let context_state_account_authority_info = next_account_info(account_info_iter)?;
367+
let _zk_token_proof_program = next_account_info(account_info_iter)?;
366368

367369
msg!("Closing equality proof context state account");
368370
invoke(

0 commit comments

Comments
 (0)