Browse Source

Add validation on load

febo 5 months ago
parent
commit
e3eee9e514

+ 1 - 1
interface/src/error.rs

@@ -124,7 +124,7 @@ impl TryFrom<u32> for TokenError {
             17 => Ok(TokenError::AccountFrozen),
             18 => Ok(TokenError::MintDecimalsMismatch),
             19 => Ok(TokenError::NonNativeNotSupported),
-            _ => Err(TokenError::InvalidInstruction.into()),
+            _ => Err(ProgramError::InvalidArgument),
         }
     }
 }

+ 31 - 11
interface/src/state/account.rs

@@ -78,11 +78,11 @@ impl Account {
     }
 
     #[inline(always)]
-    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),
+    pub fn delegate(&self) -> Option<&Pubkey> {
+        if self.delegate.0[0] == 1 {
+            Some(&self.delegate.1)
+        } else {
+            None
         }
     }
 
@@ -132,11 +132,11 @@ impl Account {
     }
 
     #[inline(always)]
-    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),
+    pub fn close_authority(&self) -> Option<&Pubkey> {
+        if self.close_authority.0[0] == 1 {
+            Some(&self.close_authority.1)
+        } else {
+            None
         }
     }
 
@@ -158,6 +158,26 @@ impl Transmutable for Account {
 impl Initializable for Account {
     #[inline(always)]
     fn is_initialized(&self) -> Result<bool, ProgramError> {
-        Ok(AccountState::try_from(self.state)? != AccountState::Uninitialized)
+        // delegate
+        match self.delegate.0 {
+            [0, 0, 0, 0] | [1, 0, 0, 0] => (),
+            _ => return Err(ProgramError::InvalidAccountData),
+        }
+        // state
+        let state = AccountState::try_from(self.state)?;
+
+        // is_native
+        match self.is_native {
+            [0, 0, 0, 0] | [1, 0, 0, 0] => (),
+            _ => return Err(ProgramError::InvalidAccountData),
+        }
+
+        // close authority
+        match self.close_authority.0 {
+            [0, 0, 0, 0] | [1, 0, 0, 0] => (),
+            _ => return Err(ProgramError::InvalidAccountData),
+        }
+
+        Ok(state != AccountState::Uninitialized)
     }
 }

+ 29 - 14
interface/src/state/mint.rs

@@ -55,11 +55,11 @@ impl Mint {
     }
 
     #[inline(always)]
-    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),
+    pub fn mint_authority(&self) -> Option<&Pubkey> {
+        if self.mint_authority.0[0] == 1 {
+            Some(&self.mint_authority.1)
+        } else {
+            None
         }
     }
 
@@ -75,11 +75,11 @@ impl Mint {
     }
 
     #[inline(always)]
-    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),
+    pub fn freeze_authority(&self) -> Option<&Pubkey> {
+        if self.freeze_authority.0[0] == 1 {
+            Some(&self.freeze_authority.1)
+        } else {
+            None
         }
     }
 }
@@ -92,10 +92,25 @@ impl Transmutable for Mint {
 impl Initializable for Mint {
     #[inline(always)]
     fn is_initialized(&self) -> Result<bool, ProgramError> {
-        match self.is_initialized {
-            0 => Ok(false),
-            1 => Ok(true),
-            _ => Err(ProgramError::InvalidAccountData),
+        // mint_authority
+        match self.mint_authority.0 {
+            [0, 0, 0, 0] | [1, 0, 0, 0] => (),
+            _ => return Err(ProgramError::InvalidAccountData),
+        }
+
+        // is_initialized
+        let initialized = match self.is_initialized {
+            0 => false,
+            1 => true,
+            _ => return Err(ProgramError::InvalidAccountData),
+        };
+
+        // freeze_authority
+        match self.freeze_authority.0 {
+            [0, 0, 0, 0] | [1, 0, 0, 0] => (),
+            _ => return Err(ProgramError::InvalidAccountData),
         }
+
+        Ok(initialized)
     }
 }

+ 4 - 0
interface/src/state/mod.rs

@@ -21,6 +21,10 @@ pub trait Transmutable {
 }
 
 /// Trait to represent a type that can be initialized.
+///
+/// Types implementing this trait must provide a method to check if the object is
+/// initialized, i.e., if all required fields are set to valid values and they
+/// represent an initialized state.
 pub trait Initializable {
     /// Return `true` if the object is initialized.
     fn is_initialized(&self) -> Result<bool, ProgramError>;

+ 1 - 0
interface/src/state/multisig.rs

@@ -46,6 +46,7 @@ impl Transmutable for Multisig {
 impl Initializable for Multisig {
     #[inline(always)]
     fn is_initialized(&self) -> Result<bool, ProgramError> {
+        // is_initialized
         match self.is_initialized {
             0 => Ok(false),
             1 => Ok(true),

+ 1 - 1
p-token/src/processor/close_account.rs

@@ -33,7 +33,7 @@ pub fn process_close_account(accounts: &[AccountInfo]) -> ProgramResult {
         }
 
         let authority = source_account
-            .close_authority()?
+            .close_authority()
             .unwrap_or(&source_account.owner);
 
         if !source_account.is_owned_by_system_program_or_incinerator() {

+ 3 - 3
p-token/src/processor/set_authority.rs

@@ -64,7 +64,7 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8])
                 }
             }
             AuthorityType::CloseAccount => {
-                let authority = account.close_authority()?.unwrap_or(&account.owner);
+                let authority = account.close_authority().unwrap_or(&account.owner);
                 validate_owner(authority, authority_info, remaining)?;
 
                 if let Some(authority) = new_authority {
@@ -86,7 +86,7 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8])
             AuthorityType::MintTokens => {
                 // Once a mint's supply is fixed, it cannot be undone by setting a new
                 // mint_authority.
-                let mint_authority = mint.mint_authority()?.ok_or(TokenError::FixedSupply)?;
+                let mint_authority = mint.mint_authority().ok_or(TokenError::FixedSupply)?;
 
                 validate_owner(mint_authority, authority_info, remaining)?;
 
@@ -100,7 +100,7 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8])
                 // Once a mint's freeze authority is disabled, it cannot be re-enabled by
                 // setting a new freeze_authority.
                 let freeze_authority = mint
-                    .freeze_authority()?
+                    .freeze_authority()
                     .ok_or(TokenError::MintCannotFreeze)?;
 
                 validate_owner(freeze_authority, authority_info, remaining)?;

+ 1 - 1
p-token/src/processor/shared/burn.rs

@@ -53,7 +53,7 @@ pub fn process_burn(
     }
 
     if !source_account.is_owned_by_system_program_or_incinerator() {
-        match source_account.delegate()? {
+        match source_account.delegate() {
             Some(delegate) if authority_info.key() == delegate => {
                 validate_owner(delegate, authority_info, remaining)?;
 

+ 1 - 1
p-token/src/processor/shared/mint_to.rs

@@ -47,7 +47,7 @@ pub fn process_mint_to(
         }
     }
 
-    match mint.mint_authority()? {
+    match mint.mint_authority() {
         Some(mint_authority) => validate_owner(mint_authority, owner_info, remaining)?,
         None => return Err(TokenError::FixedSupply.into()),
     }

+ 1 - 1
p-token/src/processor/shared/toggle_account_state.rs

@@ -34,7 +34,7 @@ pub fn process_toggle_account_state(accounts: &[AccountInfo], freeze: bool) -> P
     // passed in, one of them will fail the `load` check.
     let mint = unsafe { load::<Mint>(mint_info.borrow_data_unchecked())? };
 
-    match mint.freeze_authority()? {
+    match mint.freeze_authority() {
         Some(authority) => validate_owner(authority, authority_info, remaining),
         None => Err(TokenError::MintCannotFreeze.into()),
     }?;

+ 1 - 1
p-token/src/processor/shared/transfer.rs

@@ -126,7 +126,7 @@ pub fn process_transfer(
 
     // Validates the authority (delegate or owner).
 
-    if source_account.delegate()? == Some(authority_info.key()) {
+    if source_account.delegate() == Some(authority_info.key()) {
         validate_owner(authority_info.key(), authority_info, remaining)?;
 
         let delegated_amount = source_account

+ 1 - 1
p-token/src/processor/withdraw_excess_lamports.rs

@@ -36,7 +36,7 @@ pub fn process_withdraw_excess_lamports(accounts: &[AccountInfo]) -> ProgramResu
             // SAFETY: `source_data` has the same length as `Mint`.
             let mint = unsafe { load::<Mint>(source_data)? };
 
-            if let Some(mint_authority) = mint.mint_authority()? {
+            if let Some(mint_authority) = mint.mint_authority() {
                 validate_owner(mint_authority, authority_info, remaining)?;
             } else {
                 return Err(TokenError::AuthorityTypeNotSupported.into());