token-2022: plumb program_id through instruction builders (#2792)

* Plumb program_id into ix builders

* Don't unwrap extension instructions
This commit is contained in:
Tyera Eulberg 2022-01-24 14:14:21 -07:00 committed by GitHub
parent 3e1dd7cac8
commit cc8826ac70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 170 additions and 91 deletions

View File

@ -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::*; pub use solana_zk_token_sdk::zk_token_proof_instruction::*;
use { use {
crate::{ crate::{
extension::confidential_transfer::ConfidentialTransferMint, id, check_program_account, extension::confidential_transfer::ConfidentialTransferMint,
instruction::TokenInstruction, pod::*, instruction::TokenInstruction, pod::*,
}, },
bytemuck::{Pod, Zeroable}, bytemuck::{Pod, Zeroable},
@ -312,6 +312,7 @@ pub(crate) fn decode_instruction_data<T: Pod>(input: &[u8]) -> Result<&T, Progra
} }
fn encode_instruction<T: Pod>( fn encode_instruction<T: Pod>(
token_program_id: &Pubkey,
accounts: Vec<AccountMeta>, accounts: Vec<AccountMeta>,
instruction_type: ConfidentialTransferInstruction, instruction_type: ConfidentialTransferInstruction,
instruction_data: &T, instruction_data: &T,
@ -320,27 +321,35 @@ fn encode_instruction<T: Pod>(
data.push(ToPrimitive::to_u8(&instruction_type).unwrap()); data.push(ToPrimitive::to_u8(&instruction_type).unwrap());
data.extend_from_slice(bytemuck::bytes_of(instruction_data)); data.extend_from_slice(bytemuck::bytes_of(instruction_data));
Instruction { Instruction {
program_id: id(), program_id: *token_program_id,
accounts, accounts,
data, data,
} }
} }
/// Create a `InitializeMint` instruction /// 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<Instruction, ProgramError> {
check_program_account(token_program_id)?;
let accounts = vec![AccountMeta::new(*mint, false)]; let accounts = vec![AccountMeta::new(*mint, false)];
encode_instruction( Ok(encode_instruction(
token_program_id,
accounts, accounts,
ConfidentialTransferInstruction::InitializeMint, ConfidentialTransferInstruction::InitializeMint,
auditor, auditor,
) ))
} }
/// Create a `UpdateMint` instruction /// Create a `UpdateMint` instruction
pub fn update_mint( pub fn update_mint(
token_program_id: &Pubkey,
mint: &Pubkey, mint: &Pubkey,
new_auditor: &ConfidentialTransferMint, new_auditor: &ConfidentialTransferMint,
authority: &Pubkey, authority: &Pubkey,
) -> Instruction { ) -> Result<Instruction, ProgramError> {
check_program_account(token_program_id)?;
let accounts = vec![ let accounts = vec![
AccountMeta::new(*mint, false), AccountMeta::new(*mint, false),
AccountMeta::new_readonly(*authority, true), AccountMeta::new_readonly(*authority, true),
@ -349,23 +358,26 @@ pub fn update_mint(
new_auditor.authority != Pubkey::default(), new_auditor.authority != Pubkey::default(),
), ),
]; ];
encode_instruction( Ok(encode_instruction(
token_program_id,
accounts, accounts,
ConfidentialTransferInstruction::UpdateMint, ConfidentialTransferInstruction::UpdateMint,
new_auditor, new_auditor,
) ))
} }
/// Create a `ConfigureAccount` instruction /// Create a `ConfigureAccount` instruction
#[cfg(not(target_arch = "bpf"))] #[cfg(not(target_arch = "bpf"))]
pub fn configure_account( pub fn configure_account(
token_program_id: &Pubkey,
token_account: &Pubkey, token_account: &Pubkey,
mint: &Pubkey, mint: &Pubkey,
elgamal_pk: ElGamalPubkey, elgamal_pk: ElGamalPubkey,
decryptable_zero_balance: AeCiphertext, decryptable_zero_balance: AeCiphertext,
authority: &Pubkey, authority: &Pubkey,
multisig_signers: &[&Pubkey], multisig_signers: &[&Pubkey],
) -> Vec<Instruction> { ) -> Result<Vec<Instruction>, ProgramError> {
check_program_account(token_program_id)?;
let mut accounts = vec![ let mut accounts = vec![
AccountMeta::new(*token_account, false), AccountMeta::new(*token_account, false),
AccountMeta::new_readonly(*mint, false), AccountMeta::new_readonly(*mint, false),
@ -376,43 +388,49 @@ pub fn configure_account(
accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); accounts.push(AccountMeta::new_readonly(**multisig_signer, true));
} }
vec![encode_instruction( Ok(vec![encode_instruction(
token_program_id,
accounts, accounts,
ConfidentialTransferInstruction::ConfigureAccount, ConfidentialTransferInstruction::ConfigureAccount,
&ConfigureAccountInstructionData { &ConfigureAccountInstructionData {
elgamal_pk: elgamal_pk.into(), elgamal_pk: elgamal_pk.into(),
decryptable_zero_balance: decryptable_zero_balance.into(), decryptable_zero_balance: decryptable_zero_balance.into(),
}, },
)] )])
} }
/// Create an `ApproveAccount` instruction /// Create an `ApproveAccount` instruction
pub fn approve_account( pub fn approve_account(
token_program_id: &Pubkey,
mint: &Pubkey, mint: &Pubkey,
account_to_approve: &Pubkey, account_to_approve: &Pubkey,
authority: &Pubkey, authority: &Pubkey,
) -> Instruction { ) -> Result<Instruction, ProgramError> {
check_program_account(token_program_id)?;
let accounts = vec![ let accounts = vec![
AccountMeta::new(*account_to_approve, false), AccountMeta::new(*account_to_approve, false),
AccountMeta::new_readonly(*mint, false), AccountMeta::new_readonly(*mint, false),
AccountMeta::new_readonly(*authority, true), AccountMeta::new_readonly(*authority, true),
]; ];
encode_instruction( Ok(encode_instruction(
token_program_id,
accounts, accounts,
ConfidentialTransferInstruction::ApproveAccount, ConfidentialTransferInstruction::ApproveAccount,
&(), &(),
) ))
} }
/// Create an inner `EmptyAccount` instruction /// Create an inner `EmptyAccount` instruction
/// ///
/// This instruction is suitable for use with a cross-program `invoke` /// This instruction is suitable for use with a cross-program `invoke`
pub fn inner_empty_account( pub fn inner_empty_account(
token_program_id: &Pubkey,
token_account: &Pubkey, token_account: &Pubkey,
authority: &Pubkey, authority: &Pubkey,
multisig_signers: &[&Pubkey], multisig_signers: &[&Pubkey],
proof_instruction_offset: i8, proof_instruction_offset: i8,
) -> Instruction { ) -> Result<Instruction, ProgramError> {
check_program_account(token_program_id)?;
let mut accounts = vec![ let mut accounts = vec![
AccountMeta::new_readonly(*token_account, false), AccountMeta::new_readonly(*token_account, false),
AccountMeta::new_readonly(sysvar::instructions::id(), 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)); accounts.push(AccountMeta::new_readonly(**multisig_signer, true));
} }
encode_instruction( Ok(encode_instruction(
token_program_id,
accounts, accounts,
ConfidentialTransferInstruction::EmptyAccount, ConfidentialTransferInstruction::EmptyAccount,
&EmptyAccountInstructionData { &EmptyAccountInstructionData {
proof_instruction_offset, proof_instruction_offset,
}, },
) ))
} }
/// Create a `EmptyAccount` instruction /// Create a `EmptyAccount` instruction
pub fn empty_account( pub fn empty_account(
token_program_id: &Pubkey,
token_account: &Pubkey, token_account: &Pubkey,
authority: &Pubkey, authority: &Pubkey,
multisig_signers: &[&Pubkey], multisig_signers: &[&Pubkey],
proof_data: &CloseAccountData, proof_data: &CloseAccountData,
) -> Vec<Instruction> { ) -> Result<Vec<Instruction>, ProgramError> {
vec![ Ok(vec![
verify_close_account(proof_data), 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 /// Create a `Deposit` instruction
#[allow(clippy::too_many_arguments)]
pub fn deposit( pub fn deposit(
token_program_id: &Pubkey,
source_token_account: &Pubkey, source_token_account: &Pubkey,
mint: &Pubkey, mint: &Pubkey,
destination_token_account: &Pubkey, destination_token_account: &Pubkey,
@ -454,7 +482,8 @@ pub fn deposit(
decimals: u8, decimals: u8,
authority: &Pubkey, authority: &Pubkey,
multisig_signers: &[&Pubkey], multisig_signers: &[&Pubkey],
) -> Vec<Instruction> { ) -> Result<Vec<Instruction>, ProgramError> {
check_program_account(token_program_id)?;
let mut accounts = vec![ let mut accounts = vec![
AccountMeta::new(*source_token_account, false), AccountMeta::new(*source_token_account, false),
AccountMeta::new(*destination_token_account, false), AccountMeta::new(*destination_token_account, false),
@ -466,14 +495,15 @@ pub fn deposit(
accounts.push(AccountMeta::new_readonly(**multisig_signer, true)); accounts.push(AccountMeta::new_readonly(**multisig_signer, true));
} }
vec![encode_instruction( Ok(vec![encode_instruction(
token_program_id,
accounts, accounts,
ConfidentialTransferInstruction::Deposit, ConfidentialTransferInstruction::Deposit,
&DepositInstructionData { &DepositInstructionData {
amount: amount.into(), amount: amount.into(),
decimals, decimals,
}, },
)] )])
} }
/// Create a inner `Withdraw` instruction /// Create a inner `Withdraw` instruction
@ -481,6 +511,7 @@ pub fn deposit(
/// This instruction is suitable for use with a cross-program `invoke` /// This instruction is suitable for use with a cross-program `invoke`
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn inner_withdraw( pub fn inner_withdraw(
token_program_id: &Pubkey,
source_token_account: &Pubkey, source_token_account: &Pubkey,
destination_token_account: &Pubkey, destination_token_account: &Pubkey,
mint: &Pubkey, mint: &Pubkey,
@ -490,7 +521,8 @@ pub fn inner_withdraw(
authority: &Pubkey, authority: &Pubkey,
multisig_signers: &[&Pubkey], multisig_signers: &[&Pubkey],
proof_instruction_offset: i8, proof_instruction_offset: i8,
) -> Instruction { ) -> Result<Instruction, ProgramError> {
check_program_account(token_program_id)?;
let mut accounts = vec![ let mut accounts = vec![
AccountMeta::new(*source_token_account, false), AccountMeta::new(*source_token_account, false),
AccountMeta::new(*destination_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)); accounts.push(AccountMeta::new_readonly(**multisig_signer, true));
} }
encode_instruction( Ok(encode_instruction(
token_program_id,
accounts, accounts,
ConfidentialTransferInstruction::Withdraw, ConfidentialTransferInstruction::Withdraw,
&WithdrawInstructionData { &WithdrawInstructionData {
@ -512,13 +545,14 @@ pub fn inner_withdraw(
new_decryptable_available_balance, new_decryptable_available_balance,
proof_instruction_offset, proof_instruction_offset,
}, },
) ))
} }
/// Create a `Withdraw` instruction /// Create a `Withdraw` instruction
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
#[cfg(not(target_arch = "bpf"))] #[cfg(not(target_arch = "bpf"))]
pub fn withdraw( pub fn withdraw(
token_program_id: &Pubkey,
source_token_account: &Pubkey, source_token_account: &Pubkey,
destination_token_account: &Pubkey, destination_token_account: &Pubkey,
mint: &Pubkey, mint: &Pubkey,
@ -528,10 +562,11 @@ pub fn withdraw(
authority: &Pubkey, authority: &Pubkey,
multisig_signers: &[&Pubkey], multisig_signers: &[&Pubkey],
proof_data: &WithdrawData, proof_data: &WithdrawData,
) -> Vec<Instruction> { ) -> Result<Vec<Instruction>, ProgramError> {
vec![ Ok(vec![
verify_withdraw(proof_data), verify_withdraw(proof_data),
inner_withdraw( inner_withdraw(
token_program_id,
source_token_account, source_token_account,
destination_token_account, destination_token_account,
mint, mint,
@ -541,8 +576,8 @@ pub fn withdraw(
authority, authority,
multisig_signers, multisig_signers,
-1, -1,
), )?, // calls check_program_account
] ])
} }
/// Create a inner `Transfer` instruction /// Create a inner `Transfer` instruction
@ -550,6 +585,7 @@ pub fn withdraw(
/// This instruction is suitable for use with a cross-program `invoke` /// This instruction is suitable for use with a cross-program `invoke`
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn inner_transfer( pub fn inner_transfer(
token_program_id: &Pubkey,
source_token_account: &Pubkey, source_token_account: &Pubkey,
destination_token_account: &Pubkey, destination_token_account: &Pubkey,
mint: &Pubkey, mint: &Pubkey,
@ -557,7 +593,8 @@ pub fn inner_transfer(
authority: &Pubkey, authority: &Pubkey,
multisig_signers: &[&Pubkey], multisig_signers: &[&Pubkey],
proof_instruction_offset: i8, proof_instruction_offset: i8,
) -> Instruction { ) -> Result<Instruction, ProgramError> {
check_program_account(token_program_id)?;
let mut accounts = vec![ let mut accounts = vec![
AccountMeta::new(*source_token_account, false), AccountMeta::new(*source_token_account, false),
AccountMeta::new(*destination_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)); accounts.push(AccountMeta::new_readonly(**multisig_signer, true));
} }
encode_instruction( Ok(encode_instruction(
token_program_id,
accounts, accounts,
ConfidentialTransferInstruction::Transfer, ConfidentialTransferInstruction::Transfer,
&TransferInstructionData { &TransferInstructionData {
new_source_decryptable_available_balance, new_source_decryptable_available_balance,
proof_instruction_offset, proof_instruction_offset,
}, },
) ))
} }
/// Create a `Transfer` instruction /// Create a `Transfer` instruction
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
#[cfg(not(target_arch = "bpf"))] #[cfg(not(target_arch = "bpf"))]
pub fn transfer( pub fn transfer(
token_program_id: &Pubkey,
source_token_account: &Pubkey, source_token_account: &Pubkey,
destination_token_account: &Pubkey, destination_token_account: &Pubkey,
mint: &Pubkey, mint: &Pubkey,
@ -591,10 +630,11 @@ pub fn transfer(
authority: &Pubkey, authority: &Pubkey,
multisig_signers: &[&Pubkey], multisig_signers: &[&Pubkey],
proof_data: &TransferData, proof_data: &TransferData,
) -> Vec<Instruction> { ) -> Result<Vec<Instruction>, ProgramError> {
vec![ Ok(vec![
verify_transfer(proof_data), verify_transfer(proof_data),
inner_transfer( inner_transfer(
token_program_id,
source_token_account, source_token_account,
destination_token_account, destination_token_account,
mint, mint,
@ -602,8 +642,8 @@ pub fn transfer(
authority, authority,
multisig_signers, multisig_signers,
-1, -1,
), )?, // calls check_program_account
] ])
} }
/// Create a inner `ApplyPendingBalance` instruction /// Create a inner `ApplyPendingBalance` instruction
@ -611,12 +651,14 @@ pub fn transfer(
/// This instruction is suitable for use with a cross-program `invoke` /// This instruction is suitable for use with a cross-program `invoke`
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn inner_apply_pending_balance( pub fn inner_apply_pending_balance(
token_program_id: &Pubkey,
token_account: &Pubkey, token_account: &Pubkey,
expected_pending_balance_credit_counter: u64, expected_pending_balance_credit_counter: u64,
new_decryptable_available_balance: pod::AeCiphertext, new_decryptable_available_balance: pod::AeCiphertext,
authority: &Pubkey, authority: &Pubkey,
multisig_signers: &[&Pubkey], multisig_signers: &[&Pubkey],
) -> Instruction { ) -> Result<Instruction, ProgramError> {
check_program_account(token_program_id)?;
let mut accounts = vec![ let mut accounts = vec![
AccountMeta::new(*token_account, false), AccountMeta::new(*token_account, false),
AccountMeta::new_readonly(*authority, multisig_signers.is_empty()), 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)); accounts.push(AccountMeta::new_readonly(**multisig_signer, true));
} }
encode_instruction( Ok(encode_instruction(
token_program_id,
accounts, accounts,
ConfidentialTransferInstruction::ApplyPendingBalance, ConfidentialTransferInstruction::ApplyPendingBalance,
&ApplyPendingBalanceData { &ApplyPendingBalanceData {
expected_pending_balance_credit_counter: expected_pending_balance_credit_counter.into(), expected_pending_balance_credit_counter: expected_pending_balance_credit_counter.into(),
new_decryptable_available_balance, new_decryptable_available_balance,
}, },
) ))
} }
/// Create a `ApplyPendingBalance` instruction /// Create a `ApplyPendingBalance` instruction
#[cfg(not(target_arch = "bpf"))] #[cfg(not(target_arch = "bpf"))]
pub fn apply_pending_balance( pub fn apply_pending_balance(
token_program_id: &Pubkey,
token_account: &Pubkey, token_account: &Pubkey,
pending_balance_instructions: u64, pending_balance_instructions: u64,
new_decryptable_available_balance: AeCiphertext, new_decryptable_available_balance: AeCiphertext,
authority: &Pubkey, authority: &Pubkey,
multisig_signers: &[&Pubkey], multisig_signers: &[&Pubkey],
) -> Vec<Instruction> { ) -> Result<Vec<Instruction>, ProgramError> {
vec![inner_apply_pending_balance( Ok(vec![
token_account, inner_apply_pending_balance(
pending_balance_instructions, token_program_id,
new_decryptable_available_balance.into(), token_account,
authority, pending_balance_instructions,
multisig_signers, new_decryptable_available_balance.into(),
)] authority,
multisig_signers,
)?, // calls check_program_account
])
} }
/// Create a `EnableBalanceCredits` instruction /// Create a `EnableBalanceCredits` instruction
pub fn enable_balance_credits( pub fn enable_balance_credits(
token_program_id: &Pubkey,
token_account: &Pubkey, token_account: &Pubkey,
authority: &Pubkey, authority: &Pubkey,
multisig_signers: &[&Pubkey], multisig_signers: &[&Pubkey],
) -> Vec<Instruction> { ) -> Result<Vec<Instruction>, ProgramError> {
check_program_account(token_program_id)?;
let mut accounts = vec![ let mut accounts = vec![
AccountMeta::new(*token_account, false), AccountMeta::new(*token_account, false),
AccountMeta::new_readonly(*authority, multisig_signers.is_empty()), 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)); accounts.push(AccountMeta::new_readonly(**multisig_signer, true));
} }
vec![encode_instruction( Ok(vec![encode_instruction(
token_program_id,
accounts, accounts,
ConfidentialTransferInstruction::EnableBalanceCredits, ConfidentialTransferInstruction::EnableBalanceCredits,
&(), &(),
)] )])
} }
/// Create a `DisableBalanceCredits` instruction /// Create a `DisableBalanceCredits` instruction
#[cfg(not(target_arch = "bpf"))] #[cfg(not(target_arch = "bpf"))]
pub fn disable_balance_credits( pub fn disable_balance_credits(
token_program_id: &Pubkey,
token_account: &Pubkey, token_account: &Pubkey,
authority: &Pubkey, authority: &Pubkey,
multisig_signers: &[&Pubkey], multisig_signers: &[&Pubkey],
) -> Vec<Instruction> { ) -> Result<Vec<Instruction>, ProgramError> {
check_program_account(token_program_id)?;
let mut accounts = vec![ let mut accounts = vec![
AccountMeta::new(*token_account, false), AccountMeta::new(*token_account, false),
AccountMeta::new_readonly(*authority, multisig_signers.is_empty()), 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)); accounts.push(AccountMeta::new_readonly(**multisig_signer, true));
} }
vec![encode_instruction( Ok(vec![encode_instruction(
token_program_id,
accounts, accounts,
ConfidentialTransferInstruction::DisableBalanceCredits, ConfidentialTransferInstruction::DisableBalanceCredits,
&(), &(),
)] )])
} }

View File

@ -1,5 +1,5 @@
use { use {
crate::{error::TokenError, id, instruction::TokenInstruction}, crate::{check_program_account, error::TokenError, instruction::TokenInstruction},
solana_program::{ solana_program::{
instruction::{AccountMeta, Instruction}, instruction::{AccountMeta, Instruction},
program_error::ProgramError, program_error::ProgramError,
@ -256,12 +256,14 @@ impl TransferFeeInstruction {
/// Create a `InitializeTransferFeeConfig` instruction /// Create a `InitializeTransferFeeConfig` instruction
pub fn initialize_transfer_fee_config( pub fn initialize_transfer_fee_config(
token_program_id: &Pubkey,
mint: &Pubkey, mint: &Pubkey,
transfer_fee_config_authority: Option<&Pubkey>, transfer_fee_config_authority: Option<&Pubkey>,
withdraw_withheld_authority: Option<&Pubkey>, withdraw_withheld_authority: Option<&Pubkey>,
transfer_fee_basis_points: u16, transfer_fee_basis_points: u16,
maximum_fee: u64, maximum_fee: u64,
) -> Instruction { ) -> Result<Instruction, ProgramError> {
check_program_account(token_program_id)?;
let transfer_fee_config_authority = transfer_fee_config_authority.cloned().into(); let transfer_fee_config_authority = transfer_fee_config_authority.cloned().into();
let withdraw_withheld_authority = withdraw_withheld_authority.cloned().into(); let withdraw_withheld_authority = withdraw_withheld_authority.cloned().into();
let data = TokenInstruction::TransferFeeExtension( let data = TokenInstruction::TransferFeeExtension(
@ -274,16 +276,17 @@ pub fn initialize_transfer_fee_config(
) )
.pack(); .pack();
Instruction { Ok(Instruction {
program_id: id(), program_id: *token_program_id,
accounts: vec![AccountMeta::new(*mint, false)], accounts: vec![AccountMeta::new(*mint, false)],
data, data,
} })
} }
/// Create a `TransferCheckedWithFee` instruction /// Create a `TransferCheckedWithFee` instruction
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn transfer_checked_with_fee( pub fn transfer_checked_with_fee(
token_program_id: &Pubkey,
source: &Pubkey, source: &Pubkey,
mint: &Pubkey, mint: &Pubkey,
destination: &Pubkey, destination: &Pubkey,
@ -292,7 +295,8 @@ pub fn transfer_checked_with_fee(
amount: u64, amount: u64,
decimals: u8, decimals: u8,
fee: u64, fee: u64,
) -> Instruction { ) -> Result<Instruction, ProgramError> {
check_program_account(token_program_id)?;
let data = let data =
TokenInstruction::TransferFeeExtension(TransferFeeInstruction::TransferCheckedWithFee { TokenInstruction::TransferFeeExtension(TransferFeeInstruction::TransferCheckedWithFee {
amount, amount,
@ -310,20 +314,22 @@ pub fn transfer_checked_with_fee(
accounts.push(AccountMeta::new_readonly(**signer, true)); accounts.push(AccountMeta::new_readonly(**signer, true));
} }
Instruction { Ok(Instruction {
program_id: id(), program_id: *token_program_id,
accounts, accounts,
data, data,
} })
} }
/// Creates a `WithdrawWithheldTokensFromMint` instruction /// Creates a `WithdrawWithheldTokensFromMint` instruction
pub fn withdraw_withheld_tokens_from_mint( pub fn withdraw_withheld_tokens_from_mint(
token_program_id: &Pubkey,
mint: &Pubkey, mint: &Pubkey,
destination: &Pubkey, destination: &Pubkey,
authority: &Pubkey, authority: &Pubkey,
signers: &[&Pubkey], signers: &[&Pubkey],
) -> Instruction { ) -> Result<Instruction, ProgramError> {
check_program_account(token_program_id)?;
let mut accounts = Vec::with_capacity(3 + signers.len()); let mut accounts = Vec::with_capacity(3 + signers.len());
accounts.push(AccountMeta::new(*mint, false)); accounts.push(AccountMeta::new(*mint, false));
accounts.push(AccountMeta::new(*destination, 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)); accounts.push(AccountMeta::new_readonly(**signer, true));
} }
Instruction { Ok(Instruction {
program_id: id(), program_id: *token_program_id,
accounts, accounts,
data: TokenInstruction::TransferFeeExtension( data: TokenInstruction::TransferFeeExtension(
TransferFeeInstruction::WithdrawWithheldTokensFromMint, TransferFeeInstruction::WithdrawWithheldTokensFromMint,
) )
.pack(), .pack(),
} })
} }
/// Creates a `WithdrawWithheldTokensFromAccounts` instruction /// Creates a `WithdrawWithheldTokensFromAccounts` instruction
pub fn withdraw_withheld_tokens_from_accounts( pub fn withdraw_withheld_tokens_from_accounts(
token_program_id: &Pubkey,
mint: &Pubkey, mint: &Pubkey,
destination: &Pubkey, destination: &Pubkey,
authority: &Pubkey, authority: &Pubkey,
signers: &[&Pubkey], signers: &[&Pubkey],
sources: &[&Pubkey], sources: &[&Pubkey],
) -> Instruction { ) -> Result<Instruction, ProgramError> {
check_program_account(token_program_id)?;
let mut accounts = Vec::with_capacity(3 + signers.len() + sources.len()); let mut accounts = Vec::with_capacity(3 + signers.len() + sources.len());
accounts.push(AccountMeta::new_readonly(*mint, false)); accounts.push(AccountMeta::new_readonly(*mint, false));
accounts.push(AccountMeta::new(*destination, false)); accounts.push(AccountMeta::new(*destination, false));
@ -361,41 +369,48 @@ pub fn withdraw_withheld_tokens_from_accounts(
accounts.push(AccountMeta::new(**source, false)); accounts.push(AccountMeta::new(**source, false));
} }
Instruction { Ok(Instruction {
program_id: id(), program_id: *token_program_id,
accounts, accounts,
data: TokenInstruction::TransferFeeExtension( data: TokenInstruction::TransferFeeExtension(
TransferFeeInstruction::WithdrawWithheldTokensFromAccounts, TransferFeeInstruction::WithdrawWithheldTokensFromAccounts,
) )
.pack(), .pack(),
} })
} }
/// Creates a `HarvestWithheldTokensToMint` instruction /// 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<Instruction, ProgramError> {
check_program_account(token_program_id)?;
let mut accounts = Vec::with_capacity(1 + sources.len()); let mut accounts = Vec::with_capacity(1 + sources.len());
accounts.push(AccountMeta::new(*mint, false)); accounts.push(AccountMeta::new(*mint, false));
for source in sources.iter() { for source in sources.iter() {
accounts.push(AccountMeta::new(**source, false)); accounts.push(AccountMeta::new(**source, false));
} }
Instruction { Ok(Instruction {
program_id: id(), program_id: *token_program_id,
accounts, accounts,
data: TokenInstruction::TransferFeeExtension( data: TokenInstruction::TransferFeeExtension(
TransferFeeInstruction::HarvestWithheldTokensToMint, TransferFeeInstruction::HarvestWithheldTokensToMint,
) )
.pack(), .pack(),
} })
} }
/// Creates a `SetTransferFee` instruction /// Creates a `SetTransferFee` instruction
pub fn set_transfer_fee( pub fn set_transfer_fee(
token_program_id: &Pubkey,
mint: &Pubkey, mint: &Pubkey,
authority: &Pubkey, authority: &Pubkey,
signers: &[&Pubkey], signers: &[&Pubkey],
transfer_fee_basis_points: u16, transfer_fee_basis_points: u16,
maximum_fee: u64, maximum_fee: u64,
) -> Instruction { ) -> Result<Instruction, ProgramError> {
check_program_account(token_program_id)?;
let mut accounts = Vec::with_capacity(2 + signers.len()); let mut accounts = Vec::with_capacity(2 + signers.len());
accounts.push(AccountMeta::new(*mint, false)); accounts.push(AccountMeta::new(*mint, false));
accounts.push(AccountMeta::new_readonly(*authority, signers.is_empty())); 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)); accounts.push(AccountMeta::new_readonly(**signer, true));
} }
Instruction { Ok(Instruction {
program_id: id(), program_id: *token_program_id,
accounts, accounts,
data: TokenInstruction::TransferFeeExtension(TransferFeeInstruction::SetTransferFee { data: TokenInstruction::TransferFeeExtension(TransferFeeInstruction::SetTransferFee {
transfer_fee_basis_points, transfer_fee_basis_points,
maximum_fee, maximum_fee,
}) })
.pack(), .pack(),
} })
} }
#[cfg(test)] #[cfg(test)]

View File

@ -6615,7 +6615,8 @@ mod tests {
); );
let extended_mint_key = Pubkey::new_unique(); let extended_mint_key = Pubkey::new_unique();
do_process_instruction( 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], vec![&mut extended_mint_account],
) )
.unwrap(); .unwrap();

View File

@ -177,12 +177,14 @@ async fn single_extension() {
&spl_token_2022::id(), &spl_token_2022::id(),
), ),
transfer_fee::instruction::initialize_transfer_fee_config( transfer_fee::instruction::initialize_transfer_fee_config(
&spl_token_2022::id(),
&mint_account.pubkey(), &mint_account.pubkey(),
None, None,
None, None,
10, 10,
4242, 4242,
), )
.unwrap(),
instruction::initialize_mint( instruction::initialize_mint(
&spl_token_2022::id(), &spl_token_2022::id(),
&mint_account.pubkey(), &mint_account.pubkey(),

View File

@ -441,12 +441,14 @@ async fn fail_fee_init_after_mint_init() {
) )
.unwrap(), .unwrap(),
transfer_fee::instruction::initialize_transfer_fee_config( transfer_fee::instruction::initialize_transfer_fee_config(
&spl_token_2022::id(),
&mint_account.pubkey(), &mint_account.pubkey(),
Some(&Pubkey::new_unique()), Some(&Pubkey::new_unique()),
Some(&Pubkey::new_unique()), Some(&Pubkey::new_unique()),
10, 10,
100, 100,
), )
.unwrap(),
]; ];
let tx = Transaction::new_signed_with_payer( let tx = Transaction::new_signed_with_payer(

View File

@ -69,11 +69,18 @@ impl ExtensionInitializationParams {
} }
} }
/// Generate an appropriate initialization instruction for the given mint /// 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<Instruction, ProgramError> {
match self { match self {
Self::MintCloseAuthority { close_authority } => { Self::MintCloseAuthority { close_authority } => {
instruction::initialize_mint_close_authority(&id(), mint, close_authority.as_ref()) instruction::initialize_mint_close_authority(
.unwrap() token_program_id,
mint,
close_authority.as_ref(),
)
} }
Self::TransferFeeConfig { Self::TransferFeeConfig {
transfer_fee_config_authority, transfer_fee_config_authority,
@ -81,6 +88,7 @@ impl ExtensionInitializationParams {
transfer_fee_basis_points, transfer_fee_basis_points,
maximum_fee, maximum_fee,
} => transfer_fee::instruction::initialize_transfer_fee_config( } => transfer_fee::instruction::initialize_transfer_fee_config(
token_program_id,
mint, mint,
transfer_fee_config_authority.as_ref(), transfer_fee_config_authority.as_ref(),
withdraw_withheld_authority.as_ref(), withdraw_withheld_authority.as_ref(),
@ -189,11 +197,9 @@ where
space as u64, space as u64,
&id(), &id(),
)]; )];
let mut init_instructions = extension_initialization_params for params in extension_initialization_params {
.into_iter() instructions.push(params.instruction(&id(), &mint_pubkey)?);
.map(|e| e.instruction(&mint_pubkey)) }
.collect::<Vec<_>>();
instructions.append(&mut init_instructions);
instructions.push(instruction::initialize_mint( instructions.push(instruction::initialize_mint(
&id(), &id(),
&mint_pubkey, &mint_pubkey,