Skip to content

p-token: Fix error codes #52

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion interface/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl TryFrom<u32> for TokenError {
17 => Ok(TokenError::AccountFrozen),
18 => Ok(TokenError::MintDecimalsMismatch),
19 => Ok(TokenError::NonNativeNotSupported),
_ => Err(ProgramError::InvalidArgument),
_ => Err(TokenError::InvalidInstruction.into()),
}
}
}
6 changes: 3 additions & 3 deletions interface/src/instruction.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Instruction types.

use pinocchio::program_error::ProgramError;
use {crate::error::TokenError, pinocchio::program_error::ProgramError};

/// Instructions supported by the token program.
#[repr(u8)]
Expand Down Expand Up @@ -531,7 +531,7 @@ impl TryFrom<u8> for TokenInstruction {
match value {
// SAFETY: `value` is guaranteed to be in the range of the enum variants.
0..=24 | 38 | 255 => Ok(unsafe { core::mem::transmute::<u8, TokenInstruction>(value) }),
_ => Err(ProgramError::InvalidInstructionData),
_ => Err(TokenError::InvalidInstruction.into()),
}
}
}
Expand Down Expand Up @@ -559,7 +559,7 @@ impl TryFrom<u8> for AuthorityType {
match value {
// SAFETY: `value` is guaranteed to be in the range of the enum variants.
0..=3 => Ok(unsafe { core::mem::transmute::<u8, AuthorityType>(value) }),
_ => Err(ProgramError::InvalidInstructionData),
_ => Err(TokenError::InvalidInstruction.into()),
}
}
}
Expand Down
42 changes: 26 additions & 16 deletions interface/src/state/account.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
super::{account_state::AccountState, COption, Initializable, Transmutable},
pinocchio::pubkey::Pubkey,
pinocchio::{program_error::ProgramError, pubkey::Pubkey},
};

/// Incinerator address.
Expand All @@ -27,7 +27,7 @@ pub struct Account {
delegate: COption<Pubkey>,

/// The account's state.
pub state: AccountState,
state: u8,

/// Indicates whether this account represents a native token or not.
is_native: [u8; 4],
Expand All @@ -46,6 +46,16 @@ pub struct Account {
}

impl Account {
#[inline(always)]
pub fn set_account_state(&mut self, state: AccountState) {
self.state = state as u8;
}

#[inline(always)]
pub fn account_state(&self) -> Result<AccountState, ProgramError> {
AccountState::try_from(self.state)
}

#[inline(always)]
pub fn set_amount(&mut self, amount: u64) {
self.amount = amount.to_le_bytes();
Expand All @@ -68,11 +78,11 @@ impl Account {
}

#[inline(always)]
pub fn delegate(&self) -> Option<&Pubkey> {
if self.delegate.0[0] == 1 {
Some(&self.delegate.1)
} else {
None
pub fn delegate(&self) -> Result<Option<&Pubkey>, ProgramError> {
match self.delegate.0 {
[0, 0, 0, 0] => Ok(None),
[1, 0, 0, 0] => Ok(Some(&self.delegate.1)),
_ => Err(ProgramError::InvalidAccountData),
}
}

Expand Down Expand Up @@ -122,17 +132,17 @@ impl Account {
}

#[inline(always)]
pub fn close_authority(&self) -> Option<&Pubkey> {
if self.close_authority.0[0] == 1 {
Some(&self.close_authority.1)
} else {
None
pub fn close_authority(&self) -> Result<Option<&Pubkey>, ProgramError> {
match self.close_authority.0 {
[0, 0, 0, 0] => Ok(None),
[1, 0, 0, 0] => Ok(Some(&self.close_authority.1)),
_ => Err(ProgramError::InvalidAccountData),
}
}

#[inline(always)]
pub fn is_frozen(&self) -> bool {
self.state == AccountState::Frozen
pub fn is_frozen(&self) -> Result<bool, ProgramError> {
Ok(AccountState::try_from(self.state)? == AccountState::Frozen)
}

#[inline(always)]
Expand All @@ -147,7 +157,7 @@ impl Transmutable for Account {

impl Initializable for Account {
#[inline(always)]
fn is_initialized(&self) -> bool {
self.state != AccountState::Uninitialized
fn is_initialized(&self) -> Result<bool, ProgramError> {
Ok(AccountState::try_from(self.state)? != AccountState::Uninitialized)
}
}
15 changes: 15 additions & 0 deletions interface/src/state/account_state.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use pinocchio::program_error::ProgramError;

#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum AccountState {
Expand All @@ -13,3 +15,16 @@ pub enum AccountState {
/// this account.
Frozen,
}

impl TryFrom<u8> for AccountState {
type Error = ProgramError;

#[inline(always)]
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
// SAFETY: `value` is guaranteed to be in the range of the enum variants.
0..=2 => Ok(unsafe { core::mem::transmute::<u8, AccountState>(value) }),
_ => Err(ProgramError::InvalidAccountData),
}
}
}
34 changes: 19 additions & 15 deletions interface/src/state/mint.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
super::{COption, Initializable, Transmutable},
pinocchio::pubkey::Pubkey,
pinocchio::{program_error::ProgramError, pubkey::Pubkey},
};

/// Internal representation of a mint data.
Expand All @@ -10,7 +10,7 @@ pub struct Mint {
/// be provided during mint creation. If no mint authority is present
/// then the mint has a fixed supply and no further tokens may be
/// minted.
pub mint_authority: COption<Pubkey>,
mint_authority: COption<Pubkey>,

/// Total supply of tokens.
supply: [u8; 8],
Expand All @@ -24,7 +24,7 @@ pub struct Mint {
// Indicates whether the freeze authority is present or not.
//freeze_authority_option: [u8; 4],
/// Optional authority to freeze token accounts.
pub freeze_authority: COption<Pubkey>,
freeze_authority: COption<Pubkey>,
}

impl Mint {
Expand Down Expand Up @@ -55,11 +55,11 @@ impl Mint {
}

#[inline(always)]
pub fn mint_authority(&self) -> Option<&Pubkey> {
if self.mint_authority.0[0] == 1 {
Some(&self.mint_authority.1)
} else {
None
pub fn mint_authority(&self) -> Result<Option<&Pubkey>, ProgramError> {
match self.mint_authority.0 {
[0, 0, 0, 0] => Ok(None),
[1, 0, 0, 0] => Ok(Some(&self.mint_authority.1)),
_ => Err(ProgramError::InvalidAccountData),
}
}

Expand All @@ -75,11 +75,11 @@ impl Mint {
}

#[inline(always)]
pub fn freeze_authority(&self) -> Option<&Pubkey> {
if self.freeze_authority.0[0] == 1 {
Some(&self.freeze_authority.1)
} else {
None
pub fn freeze_authority(&self) -> Result<Option<&Pubkey>, ProgramError> {
match self.freeze_authority.0 {
[0, 0, 0, 0] => Ok(None),
[1, 0, 0, 0] => Ok(Some(&self.freeze_authority.1)),
_ => Err(ProgramError::InvalidAccountData),
}
}
}
Expand All @@ -91,7 +91,11 @@ impl Transmutable for Mint {

impl Initializable for Mint {
#[inline(always)]
fn is_initialized(&self) -> bool {
self.is_initialized == 1
fn is_initialized(&self) -> Result<bool, ProgramError> {
match self.is_initialized {
0 => Ok(false),
1 => Ok(true),
_ => Err(ProgramError::InvalidAccountData),
}
}
}
6 changes: 3 additions & 3 deletions interface/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub trait Transmutable {
/// Trait to represent a type that can be initialized.
pub trait Initializable {
/// Return `true` if the object is initialized.
fn is_initialized(&self) -> bool;
fn is_initialized(&self) -> Result<bool, ProgramError>;
}

/// Return a reference for an initialized `T` from the given bytes.
Expand All @@ -35,7 +35,7 @@ pub trait Initializable {
pub unsafe fn load<T: Initializable + Transmutable>(bytes: &[u8]) -> Result<&T, ProgramError> {
load_unchecked(bytes).and_then(|t: &T| {
// checks if the data is initialized
if t.is_initialized() {
if t.is_initialized()? {
Ok(t)
} else {
Err(ProgramError::UninitializedAccount)
Expand Down Expand Up @@ -69,7 +69,7 @@ pub unsafe fn load_mut<T: Initializable + Transmutable>(
) -> Result<&mut T, ProgramError> {
load_mut_unchecked(bytes).and_then(|t: &mut T| {
// checks if the data is initialized
if t.is_initialized() {
if t.is_initialized()? {
Ok(t)
} else {
Err(ProgramError::UninitializedAccount)
Expand Down
14 changes: 9 additions & 5 deletions interface/src/state/multisig.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
super::{Initializable, Transmutable},
pinocchio::pubkey::Pubkey,
pinocchio::{program_error::ProgramError, pubkey::Pubkey},
};

/// Minimum number of multisignature signers (min N)
Expand All @@ -18,10 +18,10 @@ pub struct Multisig {
/// Number of valid signers.
pub n: u8,

/// Is `true` if this structure has been initialized
/// Is `true` if this structure has been initialized.
is_initialized: u8,

/// Signer public keys
/// Signer public keys.
pub signers: [Pubkey; MAX_SIGNERS as usize],
}

Expand All @@ -45,7 +45,11 @@ impl Transmutable for Multisig {

impl Initializable for Multisig {
#[inline(always)]
fn is_initialized(&self) -> bool {
self.is_initialized == 1
fn is_initialized(&self) -> Result<bool, ProgramError> {
match self.is_initialized {
0 => Ok(false),
1 => Ok(true),
_ => Err(ProgramError::InvalidAccountData),
}
}
}
6 changes: 3 additions & 3 deletions p-token/src/entrypoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub fn process_instruction(
instruction_data: &[u8],
) -> ProgramResult {
let [discriminator, remaining @ ..] = instruction_data else {
return Err(ProgramError::InvalidInstructionData);
return Err(TokenError::InvalidInstruction.into());
};

let result = if *discriminator == 255 {
Expand Down Expand Up @@ -78,7 +78,7 @@ pub(crate) fn inner_process_instruction(
instruction_data: &[u8],
) -> ProgramResult {
let [discriminator, instruction_data @ ..] = instruction_data else {
return Err(ProgramError::InvalidInstructionData);
return Err(TokenError::InvalidInstruction.into());
};

match *discriminator {
Expand Down Expand Up @@ -280,6 +280,6 @@ fn inner_process_remaining_instruction(

process_withdraw_excess_lamports(accounts)
}
_ => Err(ProgramError::InvalidInstructionData),
_ => Err(TokenError::InvalidInstruction.into()),
}
}
2 changes: 1 addition & 1 deletion p-token/src/processor/amount_to_ui_amount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub fn process_amount_to_ui_amount(
let amount = u64::from_le_bytes(
instruction_data
.try_into()
.map_err(|_error| ProgramError::InvalidInstructionData)?,
.map_err(|_error| TokenError::InvalidInstruction)?,
);

let mint_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?;
Expand Down
5 changes: 3 additions & 2 deletions p-token/src/processor/approve.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use {
super::shared,
pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult},
pinocchio::{account_info::AccountInfo, ProgramResult},
spl_token_interface::error::TokenError,
};

#[inline(always)]
pub fn process_approve(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult {
let amount = u64::from_le_bytes(
instruction_data
.try_into()
.map_err(|_error| ProgramError::InvalidInstructionData)?,
.map_err(|_error| TokenError::InvalidInstruction)?,
);

shared::approve::process_approve(accounts, amount, None)
Expand Down
5 changes: 3 additions & 2 deletions p-token/src/processor/approve_checked.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use {
super::shared,
pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult},
pinocchio::{account_info::AccountInfo, ProgramResult},
spl_token_interface::error::TokenError,
};

#[inline(always)]
Expand All @@ -13,7 +14,7 @@ pub fn process_approve_checked(accounts: &[AccountInfo], instruction_data: &[u8]
decimals.first().copied(),
)
} else {
return Err(ProgramError::InvalidInstructionData);
return Err(TokenError::InvalidInstruction.into());
};

shared::approve::process_approve(accounts, amount, decimals)
Expand Down
5 changes: 3 additions & 2 deletions p-token/src/processor/batch.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use {
crate::entrypoint::inner_process_instruction,
pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult},
spl_token_interface::error::TokenError,
};

/// The size of the batch instruction header.
Expand All @@ -17,7 +18,7 @@ pub fn process_batch(mut accounts: &[AccountInfo], mut instruction_data: &[u8])

if instruction_data.len() < IX_HEADER_SIZE {
// The instruction data must have at least two bytes.
return Err(ProgramError::InvalidInstructionData);
return Err(TokenError::InvalidInstruction.into());
}

// SAFETY: The instruction data is guaranteed to have at least two bytes
Expand All @@ -27,7 +28,7 @@ pub fn process_batch(mut accounts: &[AccountInfo], mut instruction_data: &[u8])
let data_offset = IX_HEADER_SIZE + unsafe { *instruction_data.get_unchecked(1) as usize };

if instruction_data.len() < data_offset || data_offset == IX_HEADER_SIZE {
return Err(ProgramError::InvalidInstructionData);
return Err(TokenError::InvalidInstruction.into());
}

if accounts.len() < expected_accounts {
Expand Down
5 changes: 3 additions & 2 deletions p-token/src/processor/burn.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use {
super::shared,
pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult},
pinocchio::{account_info::AccountInfo, ProgramResult},
spl_token_interface::error::TokenError,
};

#[inline(always)]
pub fn process_burn(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult {
let amount = u64::from_le_bytes(
instruction_data
.try_into()
.map_err(|_error| ProgramError::InvalidInstructionData)?,
.map_err(|_error| TokenError::InvalidInstruction)?,
);

shared::burn::process_burn(accounts, amount, None)
Expand Down
Loading