diff --git a/token/cli/src/main.rs b/token/cli/src/main.rs index 96944aa2b92..c702545870e 100644 --- a/token/cli/src/main.rs +++ b/token/cli/src/main.rs @@ -39,7 +39,10 @@ use spl_associated_token_account::get_associated_token_address_with_program_id; use spl_token_2022::{ extension::{ confidential_transfer::{ - account_info::{ApplyPendingBalanceAccountInfo, WithdrawAccountInfo}, + account_info::{ + ApplyPendingBalanceAccountInfo, TransferAccountInfo, WithdrawAccountInfo, + }, + instruction::{CloseSplitContextStateAccounts, TransferSplitContextStateAccounts}, ConfidentialTransferAccount, ConfidentialTransferMint, }, confidential_transfer_fee::ConfidentialTransferFeeConfig, @@ -61,6 +64,7 @@ use spl_token_2022::{ elgamal::{self, ElGamalKeypair}, }, zk_token_elgamal::pod::ElGamalPubkey, + zk_token_proof_program, }, state::{Account, AccountState, Mint}, }; @@ -1687,21 +1691,136 @@ async fn command_transfer( pubkey.try_into().expect("Invalid auditor ElGamal pubkey"); auditor_elgamal_pubkey }); + let context_state_authority = config.fee_payer()?; + let equality_proof_context_state_account = Keypair::new(); + let ciphertext_validity_proof_context_state_account = Keypair::new(); + let range_proof_context_state_account = Keypair::new(); + let lamport_destination = &context_state_authority.pubkey(); + let zk_token_proof_program = &zk_token_proof_program::id(); + let close_split_context_state_accounts = Some(CloseSplitContextStateAccounts { + lamport_destination, + zk_token_proof_program, + }); + let transfer_context_state_accounts = TransferSplitContextStateAccounts { + equality_proof: &equality_proof_context_state_account.pubkey(), + ciphertext_validity_proof: &ciphertext_validity_proof_context_state_account + .pubkey(), + range_proof: &range_proof_context_state_account.pubkey(), + authority: &context_state_authority.pubkey(), + no_op_on_uninitialized_split_context_state: false, + close_split_context_state_accounts, + }; + + //let equality_and_ciphertext_validity_proof_signers = bulk_signers.iter().cloned().chain([equality_proof_context_state_account, ciphertext_validity_proof_context_state_account].into_iter()).collect::>(); + //let range_proof_signers = bulk_signers.iter().cloned().chain(std::iter::once(range_proof_context_state_account)).collect::>(); + + let state = token.get_account_info(&sender).await.unwrap(); + let extension = state + .get_extension::() + .unwrap(); + let transfer_account_info = TransferAccountInfo::new(extension); + + let ( + equality_proof_data, + ciphertext_validity_proof_data, + range_proof_data, + source_decrypt_handles, + ) = transfer_account_info + .generate_split_transfer_proof_data( + transfer_balance, + &args.sender_elgamal_keypair, + &args.sender_aes_key, + &recipient_elgamal_pubkey, + auditor_elgamal_pubkey.as_ref(), + ) + .unwrap(); + + token + .create_range_proof_context_state_for_transfer( + transfer_context_state_accounts, + &range_proof_data, + &[&range_proof_context_state_account], + ) + .await + .unwrap(); + token - .confidential_transfer_transfer( + .create_equality_and_ciphertext_validity_proof_context_states_for_transfer( + transfer_context_state_accounts, + &equality_proof_data, + &ciphertext_validity_proof_data, + &[ + &equality_proof_context_state_account, + &ciphertext_validity_proof_context_state_account, + ], + ) + .await + .unwrap(); + + token + .confidential_transfer_transfer_with_split_proofs( &sender, &recipient_token_account, &sender_owner, - None, + transfer_context_state_accounts, transfer_balance, - None, + Some(transfer_account_info), + &args.sender_aes_key, + &source_decrypt_handles, + &bulk_signers, + ) + .await + .unwrap(); + + // close context state accounts + token + .confidential_transfer_close_context_state( + &equality_proof_context_state_account.pubkey(), + &sender, + &context_state_authority.pubkey(), + &[context_state_authority.as_ref()], + ) + .await + .unwrap(); + + token + .confidential_transfer_close_context_state( + &ciphertext_validity_proof_context_state_account.pubkey(), + &sender, + &context_state_authority.pubkey(), + &[context_state_authority.as_ref()], + ) + .await + .unwrap(); + + token + .confidential_transfer_close_context_state( + &range_proof_context_state_account.pubkey(), + &sender, + &context_state_authority.pubkey(), + &[context_state_authority], + ) + .await? + + /* + token + .confidential_transfer_transfer_with_split_proofs_in_parallel( + &sender, + &recipient_token_account, + &sender_owner, + transfer_context_state_accounts, + transfer_balance, + None, // TODO reuse the source account fetched much earlier &args.sender_elgamal_keypair, &args.sender_aes_key, &recipient_elgamal_pubkey, auditor_elgamal_pubkey.as_ref(), - &bulk_signers, + &equality_and_ciphertext_validity_proof_signers, + &range_proof_signers, ) .await? + .1 + */ } (None, Some(_), Some(_)) => { panic!("Confidential transfer with fee is not yet supported."); @@ -5188,7 +5307,6 @@ fn app<'a, 'b>( .validator(is_valid_pubkey) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) - .conflicts_with("token") .help("The address of the token account to configure confidential transfers for \ [default: owner's associated token account]") ) @@ -5227,7 +5345,6 @@ fn app<'a, 'b>( .validator(is_valid_pubkey) .value_name("TOKEN_ACCOUNT_ADDRESS") .takes_value(true) - .conflicts_with("token") .help("The address of the token account to configure confidential transfers for \ [default: owner's associated token account]") ) diff --git a/token/client/src/token.rs b/token/client/src/token.rs index 34f17303651..ca71dff93da 100644 --- a/token/client/src/token.rs +++ b/token/client/src/token.rs @@ -2575,15 +2575,16 @@ where } /// Close a ZK Token proof program context state - pub async fn confidential_transfer_close_context_state( + pub async fn confidential_transfer_close_context_state( &self, context_state_account: &Pubkey, lamport_destination_account: &Pubkey, - context_state_authority: &S, + context_state_authority: &Pubkey, + signing_keypairs: &S, ) -> TokenResult { let context_state_info = ContextStateInfo { context_state_account, - context_state_authority: &context_state_authority.pubkey(), + context_state_authority, }; self.process_ixs( @@ -2591,7 +2592,7 @@ where context_state_info, lamport_destination_account, )], - &[context_state_authority], + signing_keypairs, ) .await }