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

Commit 70f3975

Browse files
committed
Move state to interface crate
1 parent 55a6fee commit 70f3975

30 files changed

+428
-763
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

interface/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,5 @@ repository = { workspace = true }
88
publish = false
99

1010
[dependencies]
11-
bytemuck = { workspace = true }
1211
pinocchio = { workspace = true }
1312
pinocchio-pubkey = { workspace = true }

interface/src/instruction.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use pinocchio::{program_error::ProgramError, pubkey::Pubkey};
44

5-
use crate::{error::TokenError, state::PodCOption};
5+
use crate::error::TokenError;
66

77
/// Instructions supported by the token program.
88
#[repr(C)]
@@ -27,7 +27,7 @@ pub enum TokenInstruction<'a> {
2727
/// The authority/multisignature to mint tokens.
2828
mint_authority: Pubkey,
2929
/// The freeze authority/multisignature of the mint.
30-
freeze_authority: PodCOption<Pubkey>,
30+
freeze_authority: Option<Pubkey>,
3131
},
3232

3333
/// Initializes a new account to hold tokens. If this account is associated
@@ -147,7 +147,7 @@ pub enum TokenInstruction<'a> {
147147
/// The type of authority to update.
148148
authority_type: AuthorityType,
149149
/// The new authority
150-
new_authority: PodCOption<Pubkey>,
150+
new_authority: Option<Pubkey>,
151151
},
152152

153153
/// Mints new tokens to an account. The native mint does not support
@@ -416,7 +416,7 @@ pub enum TokenInstruction<'a> {
416416
/// The authority/multisignature to mint tokens.
417417
mint_authority: Pubkey,
418418
/// The freeze authority/multisignature of the mint.
419-
freeze_authority: PodCOption<Pubkey>,
419+
freeze_authority: Option<Pubkey>,
420420
},
421421

422422
/// Gets the required size of an account for the given mint as a

interface/src/state/account.rs

Lines changed: 154 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
use bytemuck::{Pod, Zeroable};
2-
use pinocchio::pubkey::Pubkey;
1+
use pinocchio::{
2+
account_info::{AccountInfo, Ref},
3+
program_error::ProgramError,
4+
pubkey::Pubkey,
5+
};
36

4-
use super::{PodCOption, PodU64};
7+
use crate::program::ID;
58

6-
/// Account data.
9+
use super::{account_state::AccountState, COption};
10+
11+
/// Internal representation of a token account data.
712
#[repr(C)]
8-
#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
913
pub struct Account {
1014
/// The mint associated with this account
1115
pub mint: Pubkey,
@@ -14,82 +18,179 @@ pub struct Account {
1418
pub owner: Pubkey,
1519

1620
/// The amount of tokens this account holds.
17-
pub amount: PodU64,
21+
amount: [u8; 8],
1822

1923
/// If `delegate` is `Some` then `delegated_amount` represents
20-
/// the amount authorized by the delegate
21-
pub delegate: PodCOption<Pubkey>,
24+
/// the amount authorized by the delegate.
25+
delegate: COption<Pubkey>,
26+
27+
/// The account's state.
28+
pub state: AccountState,
2229

23-
/// The account's state
24-
pub state: u8,
30+
/// Indicates whether this account represents a native token or not.
31+
is_native: [u8; 4],
2532

2633
/// If is_native.is_some, this is a native token, and the value logs the
2734
/// rent-exempt reserve. An Account is required to be rent-exempt, so
2835
/// the value is used by the Processor to ensure that wrapped SOL
2936
/// accounts do not drop below this threshold.
30-
pub is_native: PodCOption<PodU64>,
37+
native_amount: [u8; 8],
3138

32-
/// The amount delegated
33-
pub delegated_amount: PodU64,
39+
/// The amount delegated.
40+
delegated_amount: [u8; 8],
3441

3542
/// Optional authority to close the account.
36-
pub close_authority: PodCOption<Pubkey>,
43+
close_authority: COption<Pubkey>,
3744
}
3845

3946
impl Account {
40-
/// Size of the `Account` account.
41-
pub const LEN: usize = core::mem::size_of::<Self>();
47+
pub const LEN: usize = core::mem::size_of::<Account>();
4248

49+
/// Return a `TokenAccount` from the given account info.
50+
///
51+
/// This method performs owner and length validation on `AccountInfo`, safe borrowing
52+
/// the account data.
4353
#[inline]
44-
pub fn is_initialized(&self) -> bool {
45-
self.state != AccountState::Uninitialized as u8
54+
pub fn from_account_info(account_info: &AccountInfo) -> Result<Ref<Account>, ProgramError> {
55+
if account_info.data_len() != Self::LEN {
56+
return Err(ProgramError::InvalidAccountData);
57+
}
58+
if account_info.owner() != &ID {
59+
return Err(ProgramError::InvalidAccountData);
60+
}
61+
Ok(Ref::map(account_info.try_borrow_data()?, |data| unsafe {
62+
Self::from_bytes(data)
63+
}))
4664
}
4765

66+
/// Return a `TokenAccount` from the given account info.
67+
///
68+
/// This method performs owner and length validation on `AccountInfo`, but does not
69+
/// perform the borrow check.
70+
///
71+
/// # Safety
72+
///
73+
/// The caller must ensure that it is safe to borrow the account data – e.g., there are
74+
/// no mutable borrows of the account data.
4875
#[inline]
49-
pub fn is_frozen(&self) -> bool {
50-
self.state == AccountState::Frozen as u8
76+
pub unsafe fn from_account_info_unchecked(
77+
account_info: &AccountInfo,
78+
) -> Result<&Account, ProgramError> {
79+
if account_info.data_len() != Self::LEN {
80+
return Err(ProgramError::InvalidAccountData);
81+
}
82+
if account_info.owner() != &ID {
83+
return Err(ProgramError::InvalidAccountData);
84+
}
85+
Ok(Self::from_bytes(account_info.borrow_data_unchecked()))
86+
}
87+
88+
/// Return a `TokenAccount` from the given bytes.
89+
///
90+
/// # Safety
91+
///
92+
/// The caller must ensure that `bytes` contains a valid representation of `TokenAccount`.
93+
#[inline(always)]
94+
pub unsafe fn from_bytes(bytes: &[u8]) -> &Self {
95+
&*(bytes.as_ptr() as *const Account)
5196
}
5297

98+
/// Return a mutable `Mint` reference from the given bytes.
99+
///
100+
/// # Safety
101+
///
102+
/// The caller must ensure that `bytes` contains a valid representation of `Mint`.
103+
#[inline(always)]
104+
pub unsafe fn from_bytes_mut(bytes: &mut [u8]) -> &mut Self {
105+
&mut *(bytes.as_mut_ptr() as *mut Account)
106+
}
107+
108+
#[inline]
109+
pub fn set_amount(&mut self, amount: u64) {
110+
self.amount = amount.to_le_bytes();
111+
}
112+
113+
#[inline]
53114
pub fn amount(&self) -> u64 {
54-
self.amount.into()
115+
u64::from_le_bytes(self.amount)
55116
}
56-
}
57117

58-
/// Account state.
59-
#[repr(u8)]
60-
#[derive(Clone, Copy, Debug, Default, PartialEq)]
61-
pub enum AccountState {
62-
/// Account is not yet initialized
63-
#[default]
64-
Uninitialized,
65-
66-
/// Account is initialized; the account owner and/or delegate may perform
67-
/// permitted operations on this account
68-
Initialized,
69-
70-
/// Account has been frozen by the mint freeze authority. Neither the
71-
/// account owner nor the delegate are able to perform operations on
72-
/// this account.
73-
Frozen,
74-
}
118+
#[inline]
119+
pub fn clear_delegate(&mut self) {
120+
self.delegate.0[0] = 0;
121+
}
75122

76-
impl From<u8> for AccountState {
77-
fn from(value: u8) -> Self {
78-
match value {
79-
0 => AccountState::Uninitialized,
80-
1 => AccountState::Initialized,
81-
2 => AccountState::Frozen,
82-
_ => panic!("invalid account state value: {value}"),
123+
#[inline]
124+
pub fn set_delegate(&mut self, delegate: &Pubkey) {
125+
self.delegate.0[0] = 1;
126+
self.delegate.1 = *delegate;
127+
}
128+
129+
#[inline]
130+
pub fn delegate(&self) -> Option<&Pubkey> {
131+
if self.delegate.0[0] == 1 {
132+
Some(&self.delegate.1)
133+
} else {
134+
None
83135
}
84136
}
85-
}
86137

87-
impl From<AccountState> for u8 {
88-
fn from(value: AccountState) -> Self {
89-
match value {
90-
AccountState::Uninitialized => 0,
91-
AccountState::Initialized => 1,
92-
AccountState::Frozen => 2,
138+
#[inline]
139+
pub fn set_native(&mut self, value: bool) {
140+
self.is_native[0] = value as u8;
141+
}
142+
143+
#[inline]
144+
pub fn is_native(&self) -> bool {
145+
self.is_native[0] == 1
146+
}
147+
148+
#[inline]
149+
pub fn native_amount(&self) -> Option<u64> {
150+
if self.is_native() {
151+
Some(u64::from_le_bytes(self.native_amount))
152+
} else {
153+
None
93154
}
94155
}
156+
157+
#[inline]
158+
pub fn set_delegated_amount(&mut self, amount: u64) {
159+
self.delegated_amount = amount.to_le_bytes();
160+
}
161+
162+
#[inline]
163+
pub fn delegated_amount(&self) -> u64 {
164+
u64::from_le_bytes(self.delegated_amount)
165+
}
166+
167+
#[inline]
168+
pub fn clear_close_authority(&mut self) {
169+
self.close_authority.0[0] = 0;
170+
}
171+
172+
#[inline]
173+
pub fn set_close_authority(&mut self, value: &Pubkey) {
174+
self.close_authority.0[0] = 1;
175+
self.close_authority.1 = *value;
176+
}
177+
178+
#[inline]
179+
pub fn close_authority(&self) -> Option<&Pubkey> {
180+
if self.close_authority.0[0] == 1 {
181+
Some(&self.close_authority.1)
182+
} else {
183+
None
184+
}
185+
}
186+
187+
#[inline(always)]
188+
pub fn is_initialized(&self) -> bool {
189+
self.state != AccountState::Uninitialized
190+
}
191+
192+
#[inline(always)]
193+
pub fn is_frozen(&self) -> bool {
194+
self.state == AccountState::Frozen
195+
}
95196
}
File renamed without changes.

0 commit comments

Comments
 (0)