use airdrop_api::{
consts::{CAMPAIGN_STATUS_ACTIVE, MINT_AUTHORITY},
instruction::MintTokens,
loaders::AirdropAccountInfoValidation,
pda::{campaign_pda, mint_authority_pda},
};
use airdrop_api::{Campaign, AirdropError};
use solana_program::clock::Clock;
use steel::*;
pub fn process_mint_tokens(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult {
let args = MintTokens::try_from_bytes(data)?;
let campaign_id = args.campaign_id;
let amount = u64::from_le_bytes(args.amount);
if amount == 0 {
return Err(AirdropError::InvalidAmount.into());
}
let [campaign_owner_info, campaign_info, mint_info, mint_authority_info, treasury_tokens_info, token_program] =
accounts
else {
return Err(ProgramError::NotEnoughAccountKeys);
};
campaign_owner_info.is_signer()?;
let (expected_campaign, _campaign_bump) = campaign_pda(&campaign_id);
campaign_info
.is_writable()?
.has_address(&expected_campaign)?;
let campaign = campaign_info
.is_campaign()?
.as_account_mut::<Campaign>(&airdrop_api::ID)?
.assert_mut(|c| c.owner == *campaign_owner_info.key)?
.assert_mut(|c| c.status == CAMPAIGN_STATUS_ACTIVE)?;
mint_info.has_address(&campaign.mint)?;
let mint_data = mint_info.as_mint()?;
let (expected_mint_authority, _mint_authority_bump) = mint_authority_pda(&campaign.mint);
mint_authority_info.has_address(&expected_mint_authority)?;
if mint_data.mint_authority() == solana_program::program_option::COption::None {
return Err(AirdropError::MintAuthorityRevoked.into());
}
if mint_data.mint_authority() != solana_program::program_option::COption::Some(expected_mint_authority) {
return Err(AirdropError::InvalidMintAuthority.into());
}
treasury_tokens_info
.is_writable()?
.has_address(&campaign.treasury)?;
token_program.is_program(&spl_token::ID)?;
let current_supply = mint_data.supply();
let new_supply = current_supply
.checked_add(amount)
.ok_or(ProgramError::ArithmeticOverflow)?;
if campaign.max_supply > 0 && new_supply > campaign.max_supply {
return Err(AirdropError::MaxSupplyExceeded.into());
}
mint_to_signed(
mint_info,
treasury_tokens_info,
mint_authority_info,
token_program,
amount,
&[MINT_AUTHORITY, campaign.mint.as_ref()], )?;
let mint_data_after = mint_info.as_mint()?;
let final_supply = mint_data_after.supply();
let clock = Clock::get()?;
airdrop_api::event::TokensMintedEvent {
campaign: *campaign_info.key,
mint: campaign.mint,
amount,
new_supply: final_supply,
minted_at: clock.unix_timestamp,
}
.log();
Ok(())
}