Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.
Merged
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
15 changes: 8 additions & 7 deletions program/src/entrypoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ use crate::processor::{
initialize_account2::process_initialize_account2,
initialize_account3::process_initialize_account3,
initialize_immutable_owner::process_initialize_immutable_owner,
initialize_mint::{process_initialize_mint, InitializeMint},
initialize_mint::process_initialize_mint,
initialize_mint2::process_initialize_mint2,
initialize_multisig::process_initialize_multisig,
initialize_multisig2::process_initialize_multisig2,
mint_to::process_mint_to,
mint_to_checked::{process_mint_to_checked, MintToChecked},
revoke::process_revoke,
set_authority::{process_set_authority, SetAuthority},
shared::initialize_mint::InitializeMint,
sync_native::process_sync_native,
thaw_account::process_thaw_account,
transfer::process_transfer,
Expand All @@ -49,14 +50,14 @@ pub fn process_instruction(

let instruction = InitializeMint::try_from_bytes(data)?;

process_initialize_mint(accounts, &instruction, true)
process_initialize_mint(accounts, &instruction)
}
// 1 - InitializeAccount
Some((&1, _)) => {
#[cfg(feature = "logging")]
pinocchio::msg!("Instruction: InitializeAccount");

process_initialize_account(program_id, accounts, None, true)
process_initialize_account(program_id, accounts)
}
// 2 - InitializeMultisig
Some((&2, data)) => {
Expand All @@ -77,7 +78,7 @@ pub fn process_instruction(
.map_err(|_error| ProgramError::InvalidInstructionData)?,
);

process_transfer(program_id, accounts, amount, None)
process_transfer(program_id, accounts, amount)
}
// 4 - Approve
Some((&4, data)) => {
Expand All @@ -89,7 +90,7 @@ pub fn process_instruction(
.map_err(|_error| ProgramError::InvalidInstructionData)?,
);

process_approve(program_id, accounts, amount, None)
process_approve(program_id, accounts, amount)
}
// 5 - Revoke
Some((&5, _)) => {
Expand Down Expand Up @@ -121,7 +122,7 @@ pub fn process_instruction(
.map_err(|_error| ProgramError::InvalidInstructionData)?,
);

process_mint_to(program_id, accounts, amount, None)
process_mint_to(program_id, accounts, amount)
}
// 8 - Burn
Some((&8, data)) => {
Expand All @@ -133,7 +134,7 @@ pub fn process_instruction(
.map_err(|_error| ProgramError::InvalidInstructionData)?,
);

process_burn(program_id, accounts, amount, None)
process_burn(program_id, accounts, amount)
}
// 9 - CloseAccount
Some((&9, _)) => {
Expand Down
68 changes: 3 additions & 65 deletions program/src/processor/approve.rs
Original file line number Diff line number Diff line change
@@ -1,73 +1,11 @@
use pinocchio::{
account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult,
};
use token_interface::{
error::TokenError,
state::{account::Account, mint::Mint, PodCOption},
};
use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult};

use super::validate_owner;
use super::shared;

pub fn process_approve(
program_id: &Pubkey,
accounts: &[AccountInfo],
amount: u64,
expected_decimals: Option<u8>,
) -> ProgramResult {
let (source_account_info, expected_mint_info, delegate_info, owner_info, remaining) =
if let Some(expected_decimals) = expected_decimals {
let [source_account_info, expected_mint_info, delegate_info, owner_info, remaning @ ..] =
accounts
else {
return Err(ProgramError::NotEnoughAccountKeys);
};

(
source_account_info,
Some((expected_mint_info, expected_decimals)),
delegate_info,
owner_info,
remaning,
)
} else {
let [source_account_info, delegate_info, owner_info, remaning @ ..] = accounts else {
return Err(ProgramError::NotEnoughAccountKeys);
};
(
source_account_info,
None,
delegate_info,
owner_info,
remaning,
)
};

let source_account = bytemuck::try_from_bytes_mut::<Account>(unsafe {
source_account_info.borrow_mut_data_unchecked()
})
.map_err(|_error| ProgramError::InvalidAccountData)?;

if source_account.is_frozen() {
return Err(TokenError::AccountFrozen.into());
}

if let Some((mint_info, expected_decimals)) = expected_mint_info {
if mint_info.key() != &source_account.mint {
return Err(TokenError::MintMismatch.into());
}

let mint = bytemuck::try_from_bytes::<Mint>(unsafe { mint_info.borrow_data_unchecked() })
.map_err(|_error| ProgramError::InvalidAccountData)?;

if expected_decimals != mint.decimals {
return Err(TokenError::MintDecimalsMismatch.into());
}
}

validate_owner(program_id, &source_account.owner, owner_info, remaining)?;

source_account.delegate = PodCOption::some(*delegate_info.key());
source_account.delegated_amount = amount.into();

Ok(())
shared::approve::process_approve(program_id, accounts, amount, None)
}
4 changes: 2 additions & 2 deletions program/src/processor/approve_checked.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use pinocchio::{
account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult,
};

use super::approve::process_approve;
use super::shared;

#[inline(always)]
pub fn process_approve_checked(
Expand All @@ -13,7 +13,7 @@ pub fn process_approve_checked(
amount: u64,
decimals: u8,
) -> ProgramResult {
process_approve(program_id, accounts, amount, Some(decimals))
shared::approve::process_approve(program_id, accounts, amount, Some(decimals))
}

pub struct ApproveChecked<'a> {
Expand Down
90 changes: 4 additions & 86 deletions program/src/processor/burn.rs
Original file line number Diff line number Diff line change
@@ -1,89 +1,7 @@
use pinocchio::{
account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult,
};
use token_interface::{
error::TokenError,
state::{account::Account, mint::Mint},
};
use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult};

use super::{check_account_owner, is_owned_by_system_program_or_incinerator, validate_owner};
use super::shared;

/// Processes a [Burn](enum.TokenInstruction.html) instruction.
pub fn process_burn(
program_id: &Pubkey,
accounts: &[AccountInfo],
amount: u64,
expected_decimals: Option<u8>,
) -> ProgramResult {
let [source_account_info, mint_info, authority_info, remaining @ ..] = accounts else {
return Err(ProgramError::NotEnoughAccountKeys);
};

// Safety: There are no conflicting borrows – the source account is only borrowed once.
let source_account = bytemuck::try_from_bytes_mut::<Account>(unsafe {
source_account_info.borrow_mut_data_unchecked()
})
.map_err(|_error| ProgramError::InvalidAccountData)?;

if source_account.is_frozen() {
return Err(TokenError::AccountFrozen.into());
}
if source_account.is_native.is_some() {
return Err(TokenError::NativeNotSupported.into());
}

// Ensure the source account has the sufficient amount. This is done before
// the value is updated on the account.
let updated_source_amount = u64::from(source_account.amount)
.checked_sub(amount)
.ok_or(TokenError::InsufficientFunds)?;

// Safety: There are no conflicting borrows – the mint account is only borrowed once.
let mint =
bytemuck::try_from_bytes_mut::<Mint>(unsafe { mint_info.borrow_mut_data_unchecked() })
.map_err(|_error| ProgramError::InvalidAccountData)?;

if mint_info.key() != &source_account.mint {
return Err(TokenError::MintMismatch.into());
}

if let Some(expected_decimals) = expected_decimals {
if expected_decimals != mint.decimals {
return Err(TokenError::MintDecimalsMismatch.into());
}
}

if !is_owned_by_system_program_or_incinerator(&source_account.owner) {
match source_account.delegate.as_ref() {
Some(delegate) if authority_info.key() == delegate => {
validate_owner(program_id, delegate, authority_info, remaining)?;

let delegated_amount = u64::from(source_account.delegated_amount)
.checked_sub(amount)
.ok_or(TokenError::InsufficientFunds)?;
source_account.delegated_amount = delegated_amount.into();

if delegated_amount == 0 {
source_account.delegate.clear();
}
}
_ => {
validate_owner(program_id, &source_account.owner, authority_info, remaining)?;
}
}
}

if amount == 0 {
check_account_owner(program_id, source_account_info)?;
check_account_owner(program_id, mint_info)?;
}

source_account.amount = updated_source_amount.into();

let mint_supply = u64::from(mint.supply)
.checked_sub(amount)
.ok_or(TokenError::Overflow)?;
mint.supply = mint_supply.into();

Ok(())
pub fn process_burn(program_id: &Pubkey, accounts: &[AccountInfo], amount: u64) -> ProgramResult {
shared::burn::process_burn(program_id, accounts, amount, None)
}
4 changes: 2 additions & 2 deletions program/src/processor/burn_checked.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use pinocchio::{
account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult,
};

use super::burn::process_burn;
use super::shared;

#[inline(always)]
pub fn process_burn_checked(
Expand All @@ -13,7 +13,7 @@ pub fn process_burn_checked(
amount: u64,
decimals: u8,
) -> ProgramResult {
process_burn(program_id, accounts, amount, Some(decimals))
shared::burn::process_burn(program_id, accounts, amount, Some(decimals))
}

pub struct BurnChecked<'a> {
Expand Down
3 changes: 1 addition & 2 deletions program/src/processor/freeze_account.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult};

use super::toggle_account_state::process_toggle_account_state;
use super::shared::toggle_account_state::process_toggle_account_state;

#[inline(always)]
pub fn process_freeze_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
process_toggle_account_state(program_id, accounts, true)
}
101 changes: 4 additions & 97 deletions program/src/processor/initialize_account.rs
Original file line number Diff line number Diff line change
@@ -1,100 +1,7 @@
use pinocchio::{
account_info::AccountInfo,
program_error::ProgramError,
pubkey::Pubkey,
sysvars::{rent::Rent, Sysvar},
ProgramResult,
};
use std::mem::size_of;
use token_interface::{
error::TokenError,
native_mint::is_native_mint,
state::{
account::{Account, AccountState},
mint::Mint,
PodCOption,
},
};
use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult};

use super::check_account_owner;
use super::shared;

pub fn process_initialize_account(
program_id: &Pubkey,
accounts: &[AccountInfo],
owner: Option<&Pubkey>,
rent_sysvar_account: bool,
) -> ProgramResult {
let (new_account_info, mint_info, owner, remaning) = if let Some(owner) = owner {
let [new_account_info, mint_info, remaning @ ..] = accounts else {
return Err(ProgramError::NotEnoughAccountKeys);
};
(new_account_info, mint_info, owner, remaning)
} else {
let [new_account_info, mint_info, owner_info, remaning @ ..] = accounts else {
return Err(ProgramError::NotEnoughAccountKeys);
};
(new_account_info, mint_info, owner_info.key(), remaning)
};

// Check rent-exempt status of the token account.

let is_exempt = if rent_sysvar_account {
let rent_sysvar_info = remaning.first().ok_or(ProgramError::NotEnoughAccountKeys)?;
let rent = unsafe { Rent::from_bytes(rent_sysvar_info.borrow_data_unchecked()) };
rent.is_exempt(new_account_info.lamports(), size_of::<Account>())
} else {
Rent::get()?.is_exempt(new_account_info.lamports(), size_of::<Account>())
};

if !is_exempt {
return Err(TokenError::NotRentExempt.into());
}

let account_data = unsafe { new_account_info.borrow_mut_data_unchecked() };
let account = bytemuck::try_from_bytes_mut::<Account>(account_data)
.map_err(|_error| ProgramError::InvalidAccountData)?;

if account.is_initialized() {
return Err(TokenError::AlreadyInUse.into());
}

let is_native_mint = is_native_mint(mint_info.key());

if !is_native_mint {
check_account_owner(program_id, mint_info)?;

let mint_data = unsafe { mint_info.borrow_data_unchecked() };
let mint = bytemuck::try_from_bytes::<Mint>(mint_data)
.map_err(|_error| ProgramError::InvalidAccountData)?;

if !bool::from(mint.is_initialized) {
return Err(TokenError::InvalidMint.into());
}
}

account.mint = *mint_info.key();
account.owner = *owner;
account.close_authority.clear();
account.delegate.clear();
account.delegated_amount = 0u64.into();
account.state = AccountState::Initialized as u8;

if is_native_mint {
let rent = Rent::get()?;
let rent_exempt_reserve = rent.minimum_balance(size_of::<Account>());

account.is_native = PodCOption::from(Some(rent_exempt_reserve.into()));
unsafe {
account.amount = new_account_info
.borrow_lamports_unchecked()
.checked_sub(rent_exempt_reserve)
.ok_or(TokenError::Overflow)?
.into()
}
} else {
account.is_native.clear();
account.amount = 0u64.into();
};

Ok(())
pub fn process_initialize_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
shared::initialize_account::process_initialize_account(program_id, accounts, None, true)
}
Loading