|
| 1 | +use pinocchio::{ |
| 2 | + account_info::AccountInfo, |
| 3 | + program_error::ProgramError, |
| 4 | + sysvars::{rent::Rent, Sysvar}, |
| 5 | + ProgramResult, |
| 6 | +}; |
| 7 | +use spl_token_interface::{ |
| 8 | + error::TokenError, |
| 9 | + state::{account::Account, load, mint::Mint, multisig::Multisig, Transmutable}, |
| 10 | +}; |
| 11 | + |
| 12 | +use super::validate_owner; |
| 13 | + |
| 14 | +#[inline(always)] |
| 15 | +pub fn process_withdraw_excess_lamports(accounts: &[AccountInfo]) -> ProgramResult { |
| 16 | + let [source_account_info, destination_info, authority_info, remaining @ ..] = accounts else { |
| 17 | + return Err(ProgramError::NotEnoughAccountKeys); |
| 18 | + }; |
| 19 | + |
| 20 | + // SAFETY: single mutable borrow to `source_account_info` account data |
| 21 | + let source_data = unsafe { source_account_info.borrow_data_unchecked() }; |
| 22 | + |
| 23 | + match source_data.len() { |
| 24 | + Account::LEN => { |
| 25 | + let account = unsafe { load::<Account>(source_data)? }; |
| 26 | + |
| 27 | + if account.is_native() { |
| 28 | + return Err(TokenError::NativeNotSupported.into()); |
| 29 | + } |
| 30 | + |
| 31 | + validate_owner(&account.owner, authority_info, remaining)?; |
| 32 | + } |
| 33 | + Mint::LEN => { |
| 34 | + let mint = unsafe { load::<Mint>(source_data)? }; |
| 35 | + |
| 36 | + if let Some(mint_authority) = mint.mint_authority() { |
| 37 | + validate_owner(mint_authority, authority_info, remaining)?; |
| 38 | + } else { |
| 39 | + return Err(TokenError::AuthorityTypeNotSupported.into()); |
| 40 | + } |
| 41 | + } |
| 42 | + Multisig::LEN => { |
| 43 | + validate_owner(source_account_info.key(), authority_info, remaining)?; |
| 44 | + } |
| 45 | + _ => return Err(TokenError::InvalidState.into()), |
| 46 | + } |
| 47 | + |
| 48 | + let source_rent_exempt_reserve = Rent::get()?.minimum_balance(source_data.len()); |
| 49 | + |
| 50 | + let transfer_amount = source_account_info |
| 51 | + .lamports() |
| 52 | + .checked_sub(source_rent_exempt_reserve) |
| 53 | + .ok_or(TokenError::NotRentExempt)?; |
| 54 | + |
| 55 | + let source_starting_lamports = source_account_info.lamports(); |
| 56 | + // SAFETY: single mutable borrow to `source_account_info` lamports. |
| 57 | + unsafe { |
| 58 | + // Moves the lamports out of the source account. |
| 59 | + *source_account_info.borrow_mut_lamports_unchecked() = source_starting_lamports |
| 60 | + .checked_sub(transfer_amount) |
| 61 | + .ok_or(TokenError::Overflow)?; |
| 62 | + } |
| 63 | + |
| 64 | + let destination_starting_lamports = destination_info.lamports(); |
| 65 | + // SAFETY: single mutable borrow to `destination_info` lamports. |
| 66 | + unsafe { |
| 67 | + // Moves the lamports to the destination account. |
| 68 | + *destination_info.borrow_mut_lamports_unchecked() = destination_starting_lamports |
| 69 | + .checked_add(transfer_amount) |
| 70 | + .ok_or(TokenError::Overflow)?; |
| 71 | + } |
| 72 | + |
| 73 | + Ok(()) |
| 74 | +} |
0 commit comments