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

Commit 2292dc2

Browse files
authored
token-2022: Refactor instruction encoding / decoding (#3011)
1 parent 6487cde commit 2292dc2

File tree

5 files changed

+72
-71
lines changed

5 files changed

+72
-71
lines changed

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

Lines changed: 18 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ use solana_zk_token_sdk::encryption::{auth_encryption::AeCiphertext, elgamal::El
33
pub use solana_zk_token_sdk::zk_token_proof_instruction::*;
44
use {
55
crate::{
6-
check_program_account, extension::confidential_transfer::*, instruction::TokenInstruction,
6+
check_program_account,
7+
extension::confidential_transfer::*,
8+
instruction::{encode_instruction, TokenInstruction},
79
},
810
bytemuck::{Pod, Zeroable},
9-
num_derive::{FromPrimitive, ToPrimitive},
10-
num_traits::{FromPrimitive, ToPrimitive},
11+
num_enum::{IntoPrimitive, TryFromPrimitive},
1112
solana_program::{
1213
instruction::{AccountMeta, Instruction},
1314
program_error::ProgramError,
@@ -19,7 +20,7 @@ use {
1920
};
2021

2122
/// Confidential Transfer extension instructions
22-
#[derive(Clone, Copy, Debug, FromPrimitive, ToPrimitive)]
23+
#[derive(Clone, Copy, Debug, TryFromPrimitive, IntoPrimitive)]
2324
#[repr(u8)]
2425
pub enum ConfidentialTransferInstruction {
2526
/// Initializes confidential transfers for a mint.
@@ -434,40 +435,6 @@ pub struct WithdrawWithheldTokensFromAccountsData {
434435
pub proof_instruction_offset: i8,
435436
}
436437

437-
pub(crate) fn decode_instruction_type(
438-
input: &[u8],
439-
) -> Result<ConfidentialTransferInstruction, ProgramError> {
440-
if input.is_empty() {
441-
Err(ProgramError::InvalidInstructionData)
442-
} else {
443-
FromPrimitive::from_u8(input[0]).ok_or(ProgramError::InvalidInstructionData)
444-
}
445-
}
446-
447-
pub(crate) fn decode_instruction_data<T: Pod>(input: &[u8]) -> Result<&T, ProgramError> {
448-
if input.is_empty() {
449-
Err(ProgramError::InvalidInstructionData)
450-
} else {
451-
pod_from_bytes(&input[1..])
452-
}
453-
}
454-
455-
fn encode_instruction<T: Pod>(
456-
token_program_id: &Pubkey,
457-
accounts: Vec<AccountMeta>,
458-
instruction_type: ConfidentialTransferInstruction,
459-
instruction_data: &T,
460-
) -> Instruction {
461-
let mut data = TokenInstruction::ConfidentialTransferExtension.pack();
462-
data.push(ToPrimitive::to_u8(&instruction_type).unwrap());
463-
data.extend_from_slice(bytemuck::bytes_of(instruction_data));
464-
Instruction {
465-
program_id: *token_program_id,
466-
accounts,
467-
data,
468-
}
469-
}
470-
471438
/// Create a `InitializeMint` instruction
472439
pub fn initialize_mint(
473440
token_program_id: &Pubkey,
@@ -479,6 +446,7 @@ pub fn initialize_mint(
479446
Ok(encode_instruction(
480447
token_program_id,
481448
accounts,
449+
TokenInstruction::ConfidentialTransferExtension,
482450
ConfidentialTransferInstruction::InitializeMint,
483451
ct_mint,
484452
))
@@ -503,6 +471,7 @@ pub fn update_mint(
503471
Ok(encode_instruction(
504472
token_program_id,
505473
accounts,
474+
TokenInstruction::ConfidentialTransferExtension,
506475
ConfidentialTransferInstruction::UpdateMint,
507476
new_ct_mint,
508477
))
@@ -533,6 +502,7 @@ pub fn configure_account(
533502
Ok(encode_instruction(
534503
token_program_id,
535504
accounts,
505+
TokenInstruction::ConfidentialTransferExtension,
536506
ConfidentialTransferInstruction::ConfigureAccount,
537507
&ConfigureAccountInstructionData {
538508
encryption_pubkey: encryption_pubkey.into(),
@@ -557,6 +527,7 @@ pub fn approve_account(
557527
Ok(encode_instruction(
558528
token_program_id,
559529
accounts,
530+
TokenInstruction::ConfidentialTransferExtension,
560531
ConfidentialTransferInstruction::ApproveAccount,
561532
&(),
562533
))
@@ -586,6 +557,7 @@ pub fn inner_empty_account(
586557
Ok(encode_instruction(
587558
token_program_id,
588559
accounts,
560+
TokenInstruction::ConfidentialTransferExtension,
589561
ConfidentialTransferInstruction::EmptyAccount,
590562
&EmptyAccountInstructionData {
591563
proof_instruction_offset,
@@ -640,6 +612,7 @@ pub fn deposit(
640612
Ok(encode_instruction(
641613
token_program_id,
642614
accounts,
615+
TokenInstruction::ConfidentialTransferExtension,
643616
ConfidentialTransferInstruction::Deposit,
644617
&DepositInstructionData {
645618
amount: amount.into(),
@@ -680,6 +653,7 @@ pub fn inner_withdraw(
680653
Ok(encode_instruction(
681654
token_program_id,
682655
accounts,
656+
TokenInstruction::ConfidentialTransferExtension,
683657
ConfidentialTransferInstruction::Withdraw,
684658
&WithdrawInstructionData {
685659
amount: amount.into(),
@@ -752,6 +726,7 @@ pub fn inner_transfer(
752726
Ok(encode_instruction(
753727
token_program_id,
754728
accounts,
729+
TokenInstruction::ConfidentialTransferExtension,
755730
ConfidentialTransferInstruction::Transfer,
756731
&TransferInstructionData {
757732
new_source_decryptable_available_balance,
@@ -812,6 +787,7 @@ pub fn inner_apply_pending_balance(
812787
Ok(encode_instruction(
813788
token_program_id,
814789
accounts,
790+
TokenInstruction::ConfidentialTransferExtension,
815791
ConfidentialTransferInstruction::ApplyPendingBalance,
816792
&ApplyPendingBalanceData {
817793
expected_pending_balance_credit_counter: expected_pending_balance_credit_counter.into(),
@@ -860,6 +836,7 @@ fn enable_or_disable_balance_credits(
860836
Ok(encode_instruction(
861837
token_program_id,
862838
accounts,
839+
TokenInstruction::ConfidentialTransferExtension,
863840
instruction,
864841
&(),
865842
))
@@ -923,6 +900,7 @@ pub fn inner_withdraw_withheld_tokens_from_mint(
923900
Ok(encode_instruction(
924901
token_program_id,
925902
accounts,
903+
TokenInstruction::ConfidentialTransferExtension,
926904
ConfidentialTransferInstruction::WithdrawWithheldTokensFromMint,
927905
&WithdrawWithheldTokensFromMintData {
928906
proof_instruction_offset,
@@ -985,6 +963,7 @@ pub fn inner_withdraw_withheld_tokens_from_accounts(
985963
Ok(encode_instruction(
986964
token_program_id,
987965
accounts,
966+
TokenInstruction::ConfidentialTransferExtension,
988967
ConfidentialTransferInstruction::WithdrawWithheldTokensFromAccounts,
989968
&WithdrawWithheldTokensFromAccountsData {
990969
proof_instruction_offset,
@@ -1033,6 +1012,7 @@ pub fn harvest_withheld_tokens_to_mint(
10331012
Ok(encode_instruction(
10341013
token_program_id,
10351014
accounts,
1015+
TokenInstruction::ConfidentialTransferExtension,
10361016
ConfidentialTransferInstruction::HarvestWithheldTokensToMint,
10371017
&(),
10381018
))

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use {
66
confidential_transfer::{instruction::*, *},
77
StateWithExtensions, StateWithExtensionsMut,
88
},
9+
instruction::{decode_instruction_data, decode_instruction_type},
910
processor::Processor,
1011
state::{Account, Mint},
1112
},

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

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
use {
2-
crate::{check_program_account, error::TokenError, instruction::TokenInstruction},
2+
crate::{
3+
check_program_account,
4+
instruction::{encode_instruction, TokenInstruction},
5+
},
36
num_enum::{IntoPrimitive, TryFromPrimitive},
47
solana_program::{
58
instruction::{AccountMeta, Instruction},
69
program_error::ProgramError,
710
pubkey::Pubkey,
811
},
9-
std::convert::TryFrom,
1012
};
1113

1214
/// Default Account State extension instructions
@@ -44,30 +46,6 @@ pub enum RequiredMemoTransfersInstruction {
4446
Disable,
4547
}
4648

47-
pub(crate) fn decode_instruction(
48-
input: &[u8],
49-
) -> Result<RequiredMemoTransfersInstruction, ProgramError> {
50-
if input.len() != 1 {
51-
return Err(TokenError::InvalidInstruction.into());
52-
}
53-
RequiredMemoTransfersInstruction::try_from(input[0])
54-
.map_err(|_| TokenError::InvalidInstruction.into())
55-
}
56-
57-
fn encode_instruction(
58-
token_program_id: &Pubkey,
59-
accounts: Vec<AccountMeta>,
60-
instruction_type: RequiredMemoTransfersInstruction,
61-
) -> Instruction {
62-
let mut data = TokenInstruction::MemoTransferExtension.pack();
63-
data.push(instruction_type.into());
64-
Instruction {
65-
program_id: *token_program_id,
66-
accounts,
67-
data,
68-
}
69-
}
70-
7149
/// Create an `Enable` instruction
7250
pub fn enable_required_transfer_memos(
7351
token_program_id: &Pubkey,
@@ -86,7 +64,9 @@ pub fn enable_required_transfer_memos(
8664
Ok(encode_instruction(
8765
token_program_id,
8866
accounts,
67+
TokenInstruction::MemoTransferExtension,
8968
RequiredMemoTransfersInstruction::Enable,
69+
&(),
9070
))
9171
}
9272

@@ -108,6 +88,8 @@ pub fn disable_required_transfer_memos(
10888
Ok(encode_instruction(
10989
token_program_id,
11090
accounts,
91+
TokenInstruction::MemoTransferExtension,
11192
RequiredMemoTransfersInstruction::Disable,
93+
&(),
11294
))
11395
}

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@ use {
22
crate::{
33
check_program_account,
44
extension::{
5-
memo_transfer::{
6-
instruction::{decode_instruction, RequiredMemoTransfersInstruction},
7-
MemoTransfer,
8-
},
5+
memo_transfer::{instruction::RequiredMemoTransfersInstruction, MemoTransfer},
96
StateWithExtensionsMut,
107
},
8+
instruction::decode_instruction_type,
119
processor::Processor,
1210
state::Account,
1311
},
@@ -85,8 +83,7 @@ pub(crate) fn process_instruction(
8583
) -> ProgramResult {
8684
check_program_account(program_id)?;
8785

88-
let instruction = decode_instruction(input)?;
89-
match instruction {
86+
match decode_instruction_type(input)? {
9087
RequiredMemoTransfersInstruction::Enable => {
9188
msg!("RequiredMemoTransfersInstruction::Enable");
9289
process_enable_required_memo_transfers(program_id, accounts)

token/program-2022/src/instruction.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,20 @@ use {
55
check_program_account, check_spl_token_program_account,
66
error::TokenError,
77
extension::{transfer_fee::instruction::TransferFeeInstruction, ExtensionType},
8+
pod::{pod_from_bytes, pod_get_packed_len},
89
},
10+
bytemuck::Pod,
911
solana_program::{
1012
instruction::{AccountMeta, Instruction},
1113
program_error::ProgramError,
1214
program_option::COption,
1315
pubkey::{Pubkey, PUBKEY_BYTES},
1416
system_program, sysvar,
1517
},
16-
std::{convert::TryInto, mem::size_of},
18+
std::{
19+
convert::{TryFrom, TryInto},
20+
mem::size_of,
21+
},
1722
};
1823

1924
/// Minimum number of multisignature signers (min N)
@@ -1680,6 +1685,42 @@ pub fn is_valid_signer_index(index: usize) -> bool {
16801685
(MIN_SIGNERS..=MAX_SIGNERS).contains(&index)
16811686
}
16821687

1688+
/// Utility function for decoding just the instruction type
1689+
pub(crate) fn decode_instruction_type<T: TryFrom<u8>>(input: &[u8]) -> Result<T, ProgramError> {
1690+
if input.is_empty() {
1691+
Err(ProgramError::InvalidInstructionData)
1692+
} else {
1693+
T::try_from(input[0]).map_err(|_| TokenError::InvalidInstruction.into())
1694+
}
1695+
}
1696+
1697+
/// Utility function for decoding instruction data
1698+
pub(crate) fn decode_instruction_data<T: Pod>(input: &[u8]) -> Result<&T, ProgramError> {
1699+
if input.len() != pod_get_packed_len::<T>().saturating_add(1) {
1700+
Err(ProgramError::InvalidInstructionData)
1701+
} else {
1702+
pod_from_bytes(&input[1..])
1703+
}
1704+
}
1705+
1706+
/// Utility function for encoding instruction data
1707+
pub(crate) fn encode_instruction<T: Into<u8>, D: Pod>(
1708+
token_program_id: &Pubkey,
1709+
accounts: Vec<AccountMeta>,
1710+
token_instruction_type: TokenInstruction,
1711+
instruction_type: T,
1712+
instruction_data: &D,
1713+
) -> Instruction {
1714+
let mut data = token_instruction_type.pack();
1715+
data.push(T::into(instruction_type));
1716+
data.extend_from_slice(bytemuck::bytes_of(instruction_data));
1717+
Instruction {
1718+
program_id: *token_program_id,
1719+
accounts,
1720+
data,
1721+
}
1722+
}
1723+
16831724
#[cfg(test)]
16841725
mod test {
16851726
use super::*;

0 commit comments

Comments
 (0)