approve.rs 2.8 KB

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