approve.rs 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. use {
  2. crate::processor::validate_owner,
  3. pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult},
  4. spl_token_interface::{
  5. error::TokenError,
  6. state::{account::Account, load, load_mut, mint::Mint},
  7. },
  8. };
  9. #[inline(always)]
  10. pub fn process_approve(
  11. accounts: &[AccountInfo],
  12. amount: u64,
  13. expected_decimals: Option<u8>,
  14. ) -> ProgramResult {
  15. // Accounts expected depend on whether we have the mint `decimals` or not; when
  16. // we have the mint `decimals`, we expect the mint account to be present.
  17. let (source_account_info, expected_mint_info, delegate_info, owner_info, remaining) =
  18. if let Some(expected_decimals) = expected_decimals {
  19. let [source_account_info, expected_mint_info, delegate_info, owner_info, remaining @ ..] =
  20. accounts
  21. else {
  22. return Err(ProgramError::NotEnoughAccountKeys);
  23. };
  24. (
  25. source_account_info,
  26. Some((expected_mint_info, expected_decimals)),
  27. delegate_info,
  28. owner_info,
  29. remaining,
  30. )
  31. } else {
  32. let [source_account_info, delegate_info, owner_info, remaining @ ..] = accounts else {
  33. return Err(ProgramError::NotEnoughAccountKeys);
  34. };
  35. (
  36. source_account_info,
  37. None,
  38. delegate_info,
  39. owner_info,
  40. remaining,
  41. )
  42. };
  43. // Validates source account.
  44. // SAFETY: single mutable borrow to `source_account_info` account data and
  45. // `load_mut` validates that the account is initialized.
  46. let source_account =
  47. unsafe { load_mut::<Account>(source_account_info.borrow_mut_data_unchecked())? };
  48. if source_account.is_frozen()? {
  49. return Err(TokenError::AccountFrozen.into());
  50. }
  51. if let Some((mint_info, expected_decimals)) = expected_mint_info {
  52. if mint_info.key() != &source_account.mint {
  53. return Err(TokenError::MintMismatch.into());
  54. }
  55. // SAFETY: single immutable borrow of `mint_info` account data and
  56. // `load` validates that the mint is initialized.
  57. let mint = unsafe { load::<Mint>(mint_info.borrow_data_unchecked())? };
  58. if expected_decimals != mint.decimals {
  59. return Err(TokenError::MintDecimalsMismatch.into());
  60. }
  61. }
  62. // SAFETY: `owner_info` is not currently borrowed.
  63. unsafe { validate_owner(&source_account.owner, owner_info, remaining)? };
  64. // Sets the delegate and delegated amount.
  65. source_account.set_delegate(delegate_info.key());
  66. source_account.set_delegated_amount(amount);
  67. Ok(())
  68. }