diff --git a/token/program-2022/src/extension/confidential_transfer/instruction.rs b/token/program-2022/src/extension/confidential_transfer/instruction.rs index 23514fb1..eb28ee92 100644 --- a/token/program-2022/src/extension/confidential_transfer/instruction.rs +++ b/token/program-2022/src/extension/confidential_transfer/instruction.rs @@ -3,7 +3,7 @@ use solana_zk_token_sdk::encryption::{auth_encryption::AeCiphertext, elgamal::El pub use solana_zk_token_sdk::zk_token_proof_instruction::*; use { crate::{ - extension::confidential_transfer::ConfidentialTransferMint, id, + check_program_account, extension::confidential_transfer::ConfidentialTransferMint, instruction::TokenInstruction, pod::*, }, bytemuck::{Pod, Zeroable}, @@ -312,6 +312,7 @@ pub(crate) fn decode_instruction_data(input: &[u8]) -> Result<&T, Progra } fn encode_instruction( + token_program_id: &Pubkey, accounts: Vec, instruction_type: ConfidentialTransferInstruction, instruction_data: &T, @@ -320,27 +321,35 @@ fn encode_instruction( data.push(ToPrimitive::to_u8(&instruction_type).unwrap()); data.extend_from_slice(bytemuck::bytes_of(instruction_data)); Instruction { - program_id: id(), + program_id: *token_program_id, accounts, data, } } /// Create a `InitializeMint` instruction -pub fn initialize_mint(mint: &Pubkey, auditor: &ConfidentialTransferMint) -> Instruction { +pub fn initialize_mint( + token_program_id: &Pubkey, + mint: &Pubkey, + auditor: &ConfidentialTransferMint, +) -> Result { + check_program_account(token_program_id)?; let accounts = vec![AccountMeta::new(*mint, false)]; - encode_instruction( + Ok(encode_instruction( + token_program_id, accounts, ConfidentialTransferInstruction::InitializeMint, auditor, - ) + )) } /// Create a `UpdateMint` instruction pub fn update_mint( + token_program_id: &Pubkey, mint: &Pubkey, new_auditor: &ConfidentialTransferMint, authority: &Pubkey, -) -> Instruction { +) -> Result { + check_program_account(token_program_id)?; let accounts = vec![ AccountMeta::new(*mint, false), AccountMeta::new_readonly(*authority, true), @@ -349,23 +358,26 @@ pub fn update_mint( new_auditor.authority != Pubkey::default(), ), ]; - encode_instruction( + Ok(encode_instruction( + token_program_id, accounts, ConfidentialTransferInstruction::UpdateMint, new_auditor, - ) + )) } /// Create a `ConfigureAccount` instruction #[cfg(not(target_arch = "bpf"))] pub fn configure_account( + token_program_id: &Pubkey, token_account: &Pubkey, mint: &Pubkey, elgamal_pk: ElGamalPubkey, decryptable_zero_balance: AeCiphertext, authority: &Pubkey, multisig_signers: &[&Pubkey], -) -> Vec { +) -> Result, ProgramError> { + check_program_account(token_program_id)?; let mut accounts = vec![ AccountMeta::new(*token_account, false), AccountMeta::new_readonly(*mint, false), @@ -376,43 +388,49 @@ pub fn configure_account( accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); } - vec![encode_instruction( + Ok(vec![encode_instruction( + token_program_id, accounts, ConfidentialTransferInstruction::ConfigureAccount, &ConfigureAccountInstructionData { elgamal_pk: elgamal_pk.into(), decryptable_zero_balance: decryptable_zero_balance.into(), }, - )] + )]) } /// Create an `ApproveAccount` instruction pub fn approve_account( + token_program_id: &Pubkey, mint: &Pubkey, account_to_approve: &Pubkey, authority: &Pubkey, -) -> Instruction { +) -> Result { + check_program_account(token_program_id)?; let accounts = vec![ AccountMeta::new(*account_to_approve, false), AccountMeta::new_readonly(*mint, false), AccountMeta::new_readonly(*authority, true), ]; - encode_instruction( + Ok(encode_instruction( + token_program_id, accounts, ConfidentialTransferInstruction::ApproveAccount, &(), - ) + )) } /// Create an inner `EmptyAccount` instruction /// /// This instruction is suitable for use with a cross-program `invoke` pub fn inner_empty_account( + token_program_id: &Pubkey, token_account: &Pubkey, authority: &Pubkey, multisig_signers: &[&Pubkey], proof_instruction_offset: i8, -) -> Instruction { +) -> Result { + check_program_account(token_program_id)?; let mut accounts = vec![ AccountMeta::new_readonly(*token_account, false), AccountMeta::new_readonly(sysvar::instructions::id(), false), @@ -423,30 +441,40 @@ pub fn inner_empty_account( accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); } - encode_instruction( + Ok(encode_instruction( + token_program_id, accounts, ConfidentialTransferInstruction::EmptyAccount, &EmptyAccountInstructionData { proof_instruction_offset, }, - ) + )) } /// Create a `EmptyAccount` instruction pub fn empty_account( + token_program_id: &Pubkey, token_account: &Pubkey, authority: &Pubkey, multisig_signers: &[&Pubkey], proof_data: &CloseAccountData, -) -> Vec { - vec![ +) -> Result, ProgramError> { + Ok(vec![ verify_close_account(proof_data), - inner_empty_account(token_account, authority, multisig_signers, -1), - ] + inner_empty_account( + token_program_id, + token_account, + authority, + multisig_signers, + -1, + )?, // calls check_program_account + ]) } /// Create a `Deposit` instruction +#[allow(clippy::too_many_arguments)] pub fn deposit( + token_program_id: &Pubkey, source_token_account: &Pubkey, mint: &Pubkey, destination_token_account: &Pubkey, @@ -454,7 +482,8 @@ pub fn deposit( decimals: u8, authority: &Pubkey, multisig_signers: &[&Pubkey], -) -> Vec { +) -> Result, ProgramError> { + check_program_account(token_program_id)?; let mut accounts = vec![ AccountMeta::new(*source_token_account, false), AccountMeta::new(*destination_token_account, false), @@ -466,14 +495,15 @@ pub fn deposit( accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); } - vec![encode_instruction( + Ok(vec![encode_instruction( + token_program_id, accounts, ConfidentialTransferInstruction::Deposit, &DepositInstructionData { amount: amount.into(), decimals, }, - )] + )]) } /// Create a inner `Withdraw` instruction @@ -481,6 +511,7 @@ pub fn deposit( /// This instruction is suitable for use with a cross-program `invoke` #[allow(clippy::too_many_arguments)] pub fn inner_withdraw( + token_program_id: &Pubkey, source_token_account: &Pubkey, destination_token_account: &Pubkey, mint: &Pubkey, @@ -490,7 +521,8 @@ pub fn inner_withdraw( authority: &Pubkey, multisig_signers: &[&Pubkey], proof_instruction_offset: i8, -) -> Instruction { +) -> Result { + check_program_account(token_program_id)?; let mut accounts = vec![ AccountMeta::new(*source_token_account, false), AccountMeta::new(*destination_token_account, false), @@ -503,7 +535,8 @@ pub fn inner_withdraw( accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); } - encode_instruction( + Ok(encode_instruction( + token_program_id, accounts, ConfidentialTransferInstruction::Withdraw, &WithdrawInstructionData { @@ -512,13 +545,14 @@ pub fn inner_withdraw( new_decryptable_available_balance, proof_instruction_offset, }, - ) + )) } /// Create a `Withdraw` instruction #[allow(clippy::too_many_arguments)] #[cfg(not(target_arch = "bpf"))] pub fn withdraw( + token_program_id: &Pubkey, source_token_account: &Pubkey, destination_token_account: &Pubkey, mint: &Pubkey, @@ -528,10 +562,11 @@ pub fn withdraw( authority: &Pubkey, multisig_signers: &[&Pubkey], proof_data: &WithdrawData, -) -> Vec { - vec![ +) -> Result, ProgramError> { + Ok(vec![ verify_withdraw(proof_data), inner_withdraw( + token_program_id, source_token_account, destination_token_account, mint, @@ -541,8 +576,8 @@ pub fn withdraw( authority, multisig_signers, -1, - ), - ] + )?, // calls check_program_account + ]) } /// Create a inner `Transfer` instruction @@ -550,6 +585,7 @@ pub fn withdraw( /// This instruction is suitable for use with a cross-program `invoke` #[allow(clippy::too_many_arguments)] pub fn inner_transfer( + token_program_id: &Pubkey, source_token_account: &Pubkey, destination_token_account: &Pubkey, mint: &Pubkey, @@ -557,7 +593,8 @@ pub fn inner_transfer( authority: &Pubkey, multisig_signers: &[&Pubkey], proof_instruction_offset: i8, -) -> Instruction { +) -> Result { + check_program_account(token_program_id)?; let mut accounts = vec![ AccountMeta::new(*source_token_account, false), AccountMeta::new(*destination_token_account, false), @@ -570,20 +607,22 @@ pub fn inner_transfer( accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); } - encode_instruction( + Ok(encode_instruction( + token_program_id, accounts, ConfidentialTransferInstruction::Transfer, &TransferInstructionData { new_source_decryptable_available_balance, proof_instruction_offset, }, - ) + )) } /// Create a `Transfer` instruction #[allow(clippy::too_many_arguments)] #[cfg(not(target_arch = "bpf"))] pub fn transfer( + token_program_id: &Pubkey, source_token_account: &Pubkey, destination_token_account: &Pubkey, mint: &Pubkey, @@ -591,10 +630,11 @@ pub fn transfer( authority: &Pubkey, multisig_signers: &[&Pubkey], proof_data: &TransferData, -) -> Vec { - vec![ +) -> Result, ProgramError> { + Ok(vec![ verify_transfer(proof_data), inner_transfer( + token_program_id, source_token_account, destination_token_account, mint, @@ -602,8 +642,8 @@ pub fn transfer( authority, multisig_signers, -1, - ), - ] + )?, // calls check_program_account + ]) } /// Create a inner `ApplyPendingBalance` instruction @@ -611,12 +651,14 @@ pub fn transfer( /// This instruction is suitable for use with a cross-program `invoke` #[allow(clippy::too_many_arguments)] pub fn inner_apply_pending_balance( + token_program_id: &Pubkey, token_account: &Pubkey, expected_pending_balance_credit_counter: u64, new_decryptable_available_balance: pod::AeCiphertext, authority: &Pubkey, multisig_signers: &[&Pubkey], -) -> Instruction { +) -> Result { + check_program_account(token_program_id)?; let mut accounts = vec![ AccountMeta::new(*token_account, false), AccountMeta::new_readonly(*authority, multisig_signers.is_empty()), @@ -626,40 +668,47 @@ pub fn inner_apply_pending_balance( accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); } - encode_instruction( + Ok(encode_instruction( + token_program_id, accounts, ConfidentialTransferInstruction::ApplyPendingBalance, &ApplyPendingBalanceData { expected_pending_balance_credit_counter: expected_pending_balance_credit_counter.into(), new_decryptable_available_balance, }, - ) + )) } /// Create a `ApplyPendingBalance` instruction #[cfg(not(target_arch = "bpf"))] pub fn apply_pending_balance( + token_program_id: &Pubkey, token_account: &Pubkey, pending_balance_instructions: u64, new_decryptable_available_balance: AeCiphertext, authority: &Pubkey, multisig_signers: &[&Pubkey], -) -> Vec { - vec![inner_apply_pending_balance( - token_account, - pending_balance_instructions, - new_decryptable_available_balance.into(), - authority, - multisig_signers, - )] +) -> Result, ProgramError> { + Ok(vec![ + inner_apply_pending_balance( + token_program_id, + token_account, + pending_balance_instructions, + new_decryptable_available_balance.into(), + authority, + multisig_signers, + )?, // calls check_program_account + ]) } /// Create a `EnableBalanceCredits` instruction pub fn enable_balance_credits( + token_program_id: &Pubkey, token_account: &Pubkey, authority: &Pubkey, multisig_signers: &[&Pubkey], -) -> Vec { +) -> Result, ProgramError> { + check_program_account(token_program_id)?; let mut accounts = vec![ AccountMeta::new(*token_account, false), AccountMeta::new_readonly(*authority, multisig_signers.is_empty()), @@ -669,20 +718,23 @@ pub fn enable_balance_credits( accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); } - vec![encode_instruction( + Ok(vec![encode_instruction( + token_program_id, accounts, ConfidentialTransferInstruction::EnableBalanceCredits, &(), - )] + )]) } /// Create a `DisableBalanceCredits` instruction #[cfg(not(target_arch = "bpf"))] pub fn disable_balance_credits( + token_program_id: &Pubkey, token_account: &Pubkey, authority: &Pubkey, multisig_signers: &[&Pubkey], -) -> Vec { +) -> Result, ProgramError> { + check_program_account(token_program_id)?; let mut accounts = vec![ AccountMeta::new(*token_account, false), AccountMeta::new_readonly(*authority, multisig_signers.is_empty()), @@ -692,9 +744,10 @@ pub fn disable_balance_credits( accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); } - vec![encode_instruction( + Ok(vec![encode_instruction( + token_program_id, accounts, ConfidentialTransferInstruction::DisableBalanceCredits, &(), - )] + )]) } diff --git a/token/program-2022/src/extension/transfer_fee/instruction.rs b/token/program-2022/src/extension/transfer_fee/instruction.rs index a77d8b54..357366da 100644 --- a/token/program-2022/src/extension/transfer_fee/instruction.rs +++ b/token/program-2022/src/extension/transfer_fee/instruction.rs @@ -1,5 +1,5 @@ use { - crate::{error::TokenError, id, instruction::TokenInstruction}, + crate::{check_program_account, error::TokenError, instruction::TokenInstruction}, solana_program::{ instruction::{AccountMeta, Instruction}, program_error::ProgramError, @@ -256,12 +256,14 @@ impl TransferFeeInstruction { /// Create a `InitializeTransferFeeConfig` instruction pub fn initialize_transfer_fee_config( + token_program_id: &Pubkey, mint: &Pubkey, transfer_fee_config_authority: Option<&Pubkey>, withdraw_withheld_authority: Option<&Pubkey>, transfer_fee_basis_points: u16, maximum_fee: u64, -) -> Instruction { +) -> Result { + check_program_account(token_program_id)?; let transfer_fee_config_authority = transfer_fee_config_authority.cloned().into(); let withdraw_withheld_authority = withdraw_withheld_authority.cloned().into(); let data = TokenInstruction::TransferFeeExtension( @@ -274,16 +276,17 @@ pub fn initialize_transfer_fee_config( ) .pack(); - Instruction { - program_id: id(), + Ok(Instruction { + program_id: *token_program_id, accounts: vec![AccountMeta::new(*mint, false)], data, - } + }) } /// Create a `TransferCheckedWithFee` instruction #[allow(clippy::too_many_arguments)] pub fn transfer_checked_with_fee( + token_program_id: &Pubkey, source: &Pubkey, mint: &Pubkey, destination: &Pubkey, @@ -292,7 +295,8 @@ pub fn transfer_checked_with_fee( amount: u64, decimals: u8, fee: u64, -) -> Instruction { +) -> Result { + check_program_account(token_program_id)?; let data = TokenInstruction::TransferFeeExtension(TransferFeeInstruction::TransferCheckedWithFee { amount, @@ -310,20 +314,22 @@ pub fn transfer_checked_with_fee( accounts.push(AccountMeta::new_readonly(**signer, true)); } - Instruction { - program_id: id(), + Ok(Instruction { + program_id: *token_program_id, accounts, data, - } + }) } /// Creates a `WithdrawWithheldTokensFromMint` instruction pub fn withdraw_withheld_tokens_from_mint( + token_program_id: &Pubkey, mint: &Pubkey, destination: &Pubkey, authority: &Pubkey, signers: &[&Pubkey], -) -> Instruction { +) -> Result { + check_program_account(token_program_id)?; let mut accounts = Vec::with_capacity(3 + signers.len()); accounts.push(AccountMeta::new(*mint, false)); accounts.push(AccountMeta::new(*destination, false)); @@ -332,24 +338,26 @@ pub fn withdraw_withheld_tokens_from_mint( accounts.push(AccountMeta::new_readonly(**signer, true)); } - Instruction { - program_id: id(), + Ok(Instruction { + program_id: *token_program_id, accounts, data: TokenInstruction::TransferFeeExtension( TransferFeeInstruction::WithdrawWithheldTokensFromMint, ) .pack(), - } + }) } /// Creates a `WithdrawWithheldTokensFromAccounts` instruction pub fn withdraw_withheld_tokens_from_accounts( + token_program_id: &Pubkey, mint: &Pubkey, destination: &Pubkey, authority: &Pubkey, signers: &[&Pubkey], sources: &[&Pubkey], -) -> Instruction { +) -> Result { + check_program_account(token_program_id)?; let mut accounts = Vec::with_capacity(3 + signers.len() + sources.len()); accounts.push(AccountMeta::new_readonly(*mint, false)); accounts.push(AccountMeta::new(*destination, false)); @@ -361,41 +369,48 @@ pub fn withdraw_withheld_tokens_from_accounts( accounts.push(AccountMeta::new(**source, false)); } - Instruction { - program_id: id(), + Ok(Instruction { + program_id: *token_program_id, accounts, data: TokenInstruction::TransferFeeExtension( TransferFeeInstruction::WithdrawWithheldTokensFromAccounts, ) .pack(), - } + }) } /// Creates a `HarvestWithheldTokensToMint` instruction -pub fn harvest_withheld_tokens_to_mint(mint: &Pubkey, sources: &[&Pubkey]) -> Instruction { +pub fn harvest_withheld_tokens_to_mint( + token_program_id: &Pubkey, + mint: &Pubkey, + sources: &[&Pubkey], +) -> Result { + check_program_account(token_program_id)?; let mut accounts = Vec::with_capacity(1 + sources.len()); accounts.push(AccountMeta::new(*mint, false)); for source in sources.iter() { accounts.push(AccountMeta::new(**source, false)); } - Instruction { - program_id: id(), + Ok(Instruction { + program_id: *token_program_id, accounts, data: TokenInstruction::TransferFeeExtension( TransferFeeInstruction::HarvestWithheldTokensToMint, ) .pack(), - } + }) } /// Creates a `SetTransferFee` instruction pub fn set_transfer_fee( + token_program_id: &Pubkey, mint: &Pubkey, authority: &Pubkey, signers: &[&Pubkey], transfer_fee_basis_points: u16, maximum_fee: u64, -) -> Instruction { +) -> Result { + check_program_account(token_program_id)?; let mut accounts = Vec::with_capacity(2 + signers.len()); accounts.push(AccountMeta::new(*mint, false)); accounts.push(AccountMeta::new_readonly(*authority, signers.is_empty())); @@ -403,15 +418,15 @@ pub fn set_transfer_fee( accounts.push(AccountMeta::new_readonly(**signer, true)); } - Instruction { - program_id: id(), + Ok(Instruction { + program_id: *token_program_id, accounts, data: TokenInstruction::TransferFeeExtension(TransferFeeInstruction::SetTransferFee { transfer_fee_basis_points, maximum_fee, }) .pack(), - } + }) } #[cfg(test)] diff --git a/token/program-2022/src/processor.rs b/token/program-2022/src/processor.rs index 85bab986..f19e60da 100644 --- a/token/program-2022/src/processor.rs +++ b/token/program-2022/src/processor.rs @@ -6615,7 +6615,8 @@ mod tests { ); let extended_mint_key = Pubkey::new_unique(); do_process_instruction( - initialize_transfer_fee_config(&extended_mint_key, None, None, 10, 4242), + initialize_transfer_fee_config(&program_id, &extended_mint_key, None, None, 10, 4242) + .unwrap(), vec![&mut extended_mint_account], ) .unwrap(); diff --git a/token/program-2022/tests/initialize_account.rs b/token/program-2022/tests/initialize_account.rs index ee244f76..2c958f35 100644 --- a/token/program-2022/tests/initialize_account.rs +++ b/token/program-2022/tests/initialize_account.rs @@ -177,12 +177,14 @@ async fn single_extension() { &spl_token_2022::id(), ), transfer_fee::instruction::initialize_transfer_fee_config( + &spl_token_2022::id(), &mint_account.pubkey(), None, None, 10, 4242, - ), + ) + .unwrap(), instruction::initialize_mint( &spl_token_2022::id(), &mint_account.pubkey(), diff --git a/token/program-2022/tests/initialize_mint.rs b/token/program-2022/tests/initialize_mint.rs index ebf4f554..c3a872e6 100644 --- a/token/program-2022/tests/initialize_mint.rs +++ b/token/program-2022/tests/initialize_mint.rs @@ -441,12 +441,14 @@ async fn fail_fee_init_after_mint_init() { ) .unwrap(), transfer_fee::instruction::initialize_transfer_fee_config( + &spl_token_2022::id(), &mint_account.pubkey(), Some(&Pubkey::new_unique()), Some(&Pubkey::new_unique()), 10, 100, - ), + ) + .unwrap(), ]; let tx = Transaction::new_signed_with_payer( diff --git a/token/rust/src/token.rs b/token/rust/src/token.rs index f3021cfb..c7a10312 100644 --- a/token/rust/src/token.rs +++ b/token/rust/src/token.rs @@ -69,11 +69,18 @@ impl ExtensionInitializationParams { } } /// Generate an appropriate initialization instruction for the given mint - pub fn instruction(self, mint: &Pubkey) -> Instruction { + pub fn instruction( + self, + token_program_id: &Pubkey, + mint: &Pubkey, + ) -> Result { match self { Self::MintCloseAuthority { close_authority } => { - instruction::initialize_mint_close_authority(&id(), mint, close_authority.as_ref()) - .unwrap() + instruction::initialize_mint_close_authority( + token_program_id, + mint, + close_authority.as_ref(), + ) } Self::TransferFeeConfig { transfer_fee_config_authority, @@ -81,6 +88,7 @@ impl ExtensionInitializationParams { transfer_fee_basis_points, maximum_fee, } => transfer_fee::instruction::initialize_transfer_fee_config( + token_program_id, mint, transfer_fee_config_authority.as_ref(), withdraw_withheld_authority.as_ref(), @@ -189,11 +197,9 @@ where space as u64, &id(), )]; - let mut init_instructions = extension_initialization_params - .into_iter() - .map(|e| e.instruction(&mint_pubkey)) - .collect::>(); - instructions.append(&mut init_instructions); + for params in extension_initialization_params { + instructions.push(params.instruction(&id(), &mint_pubkey)?); + } instructions.push(instruction::initialize_mint( &id(), &mint_pubkey,