use airdrop_api::{
consts::FEE_ACCOUNT, instruction::WithdrawFees, loaders::AirdropAccountInfoValidation,
pda::fee_account_pda, Config,
};
use solana_program::program::invoke_signed;
use steel::*;
pub fn process_withdraw_fees(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult {
let args = WithdrawFees::try_from_bytes(data)?;
let amount = u64::from_le_bytes(args.amount);
let [admin_info, config_info, fee_account_info, beneficiary_info, system_program] = accounts
else {
return Err(ProgramError::NotEnoughAccountKeys);
};
admin_info.is_signer()?;
let config = config_info
.is_config()?
.is_writable()?
.as_account_mut::<Config>(&airdrop_api::ID)?
.assert_mut(|c| c.admin == *admin_info.key)?;
let (expected_fee_account, fee_bump) = fee_account_pda();
fee_account_info
.is_writable()?
.has_address(&expected_fee_account)?;
beneficiary_info.is_writable()?;
system_program.is_program(&system_program::ID)?;
let current_balance = **fee_account_info.lamports.borrow();
let withdraw_amount = if amount == 0 {
current_balance } else {
amount.min(current_balance) };
if withdraw_amount == 0 {
return Err(ProgramError::InsufficientFunds);
}
invoke_signed(
&solana_program::system_instruction::transfer(
fee_account_info.key,
beneficiary_info.key,
withdraw_amount,
),
&[
fee_account_info.clone(),
beneficiary_info.clone(),
system_program.clone(),
],
&[&[FEE_ACCOUNT, &[fee_bump]]],
)?;
config.total_fees_collected = config.total_fees_collected
.checked_sub(withdraw_amount)
.ok_or(ProgramError::ArithmeticOverflow)?;
airdrop_api::event::FeesWithdrawnEvent {
admin: *admin_info.key,
beneficiary: *beneficiary_info.key,
amount: withdraw_amount,
remaining_balance: current_balance - withdraw_amount,
}
.log();
Ok(())
}