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 ) ]
913pub 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
3946impl 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}
0 commit comments