close_account.rs 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. use pinocchio::{
  2. account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult,
  3. };
  4. use token_interface::{error::TokenError, state::account::Account};
  5. use super::{is_owned_by_system_program_or_incinerator, validate_owner, INCINERATOR_ID};
  6. /// Processes a [CloseAccount](enum.TokenInstruction.html) instruction.
  7. pub fn process_close_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
  8. let [source_account_info, destination_account_info, authority_info, remaining @ ..] = accounts
  9. else {
  10. return Err(ProgramError::NotEnoughAccountKeys);
  11. };
  12. if source_account_info.key() == destination_account_info.key() {
  13. return Err(ProgramError::InvalidAccountData);
  14. }
  15. let source_account =
  16. bytemuck::try_from_bytes::<Account>(unsafe { source_account_info.borrow_data_unchecked() })
  17. .map_err(|_error| ProgramError::InvalidAccountData)?;
  18. if source_account.is_native.is_none() && source_account.amount() != 0 {
  19. return Err(TokenError::NonNativeHasBalance.into());
  20. }
  21. let authority = source_account
  22. .close_authority
  23. .get()
  24. .unwrap_or(source_account.owner);
  25. if !is_owned_by_system_program_or_incinerator(source_account_info.owner()) {
  26. validate_owner(program_id, &authority, authority_info, remaining)?;
  27. } else if destination_account_info.key() != &INCINERATOR_ID {
  28. return Err(ProgramError::InvalidAccountData);
  29. }
  30. let destination_starting_lamports = destination_account_info.lamports();
  31. unsafe {
  32. // Moves the lamports to the destination account and closes the source account.
  33. *destination_account_info.borrow_mut_lamports_unchecked() = destination_starting_lamports
  34. .checked_add(source_account_info.lamports())
  35. .ok_or(TokenError::Overflow)?;
  36. source_account_info.close();
  37. }
  38. Ok(())
  39. }