use airdrop_api::{
consts::{CAMPAIGN, CAMPAIGN_STATUS_ACTIVE, TREASURY},
instruction::CreateCampaign,
loaders::AirdropAccountInfoValidation,
pda::{campaign_pda, campaign_treasury_pda, mint_treasury_pda},
};
use airdrop_api::{AirdropError, Campaign, Config};
use solana_program::{clock::Clock, program::invoke, program_error::ProgramError};
use steel::*;
pub fn process_create_campaign(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult {
let args = CreateCampaign::try_from_bytes(data)?;
let campaign_id = args.campaign_id;
let mint = args.mint;
let merkle_root = args.merkle_root;
let recipient_count = u64::from_le_bytes(args.recipient_count);
let initial_supply = u64::from_le_bytes(args.initial_supply);
let max_supply = u64::from_le_bytes(args.max_supply);
let [payer_info, campaign_owner_info, config_info, campaign_info, mint_info, mint_treasury_info, mint_treasury_tokens_info, campaign_treasury_info, campaign_treasury_tokens_info, fee_account_info, token_program, associated_token_program, system_program, rent_sysvar] =
accounts
else {
return Err(ProgramError::NotEnoughAccountKeys);
};
payer_info.is_signer()?;
campaign_owner_info.is_signer()?;
let config = config_info
.is_config()?
.is_writable()?
.as_account_mut::<Config>(&airdrop_api::ID)?;
let (expected_campaign, _campaign_bump) = campaign_pda(&campaign_id);
campaign_info
.is_empty()?
.is_writable()?
.has_address(&expected_campaign)?;
mint_info.has_address(&mint)?;
let _mint_data = mint_info.as_mint()?;
let (expected_mint_treasury, _mint_treasury_bump) = mint_treasury_pda(&mint);
mint_treasury_info
.is_writable()?
.has_address(&expected_mint_treasury)?;
let expected_mint_treasury_tokens =
spl_associated_token_account::get_associated_token_address_with_program_id(
&expected_mint_treasury,
&mint,
&spl_token::ID,
);
mint_treasury_tokens_info
.is_writable()?
.has_address(&expected_mint_treasury_tokens)?;
let (expected_campaign_treasury, _campaign_treasury_bump) = campaign_treasury_pda(&campaign_id);
campaign_treasury_info.has_address(&expected_campaign_treasury)?;
let expected_campaign_treasury_tokens =
spl_associated_token_account::get_associated_token_address_with_program_id(
&expected_campaign_treasury,
&mint,
&spl_token::ID,
);
campaign_treasury_tokens_info
.is_writable()?
.has_address(&expected_campaign_treasury_tokens)?;
fee_account_info
.is_writable()?
.has_address(&config.fee_account)?;
token_program.is_program(&spl_token::ID)?;
associated_token_program.is_program(&spl_associated_token_account::ID)?;
system_program.is_program(&system_program::ID)?;
rent_sysvar.is_sysvar(&sysvar::rent::ID)?;
let merkle_fee = if merkle_root != [0u8; 32] {
if recipient_count == 0 {
return Err(AirdropError::InvalidAmount.into());
}
config
.merkle_fee_per_recipient_lamports
.checked_mul(recipient_count)
.ok_or(ProgramError::ArithmeticOverflow)?
} else {
0
};
if merkle_fee > 0 {
invoke(
&solana_program::system_instruction::transfer(
payer_info.key,
fee_account_info.key,
merkle_fee,
),
&[
payer_info.clone(),
fee_account_info.clone(),
system_program.clone(),
],
)?;
config.total_fees_collected = config
.total_fees_collected
.checked_add(merkle_fee)
.ok_or(ProgramError::ArithmeticOverflow)?;
}
let clock = Clock::get()?;
create_program_account::<Campaign>(
campaign_info,
system_program,
payer_info,
&airdrop_api::ID,
&[CAMPAIGN, &campaign_id],
)?;
let campaign = campaign_info.as_account_mut::<Campaign>(&airdrop_api::ID)?;
campaign.owner = *campaign_owner_info.key;
campaign.mint = *mint_info.key;
campaign.treasury = *campaign_treasury_tokens_info.key;
campaign.merkle_root = merkle_root;
campaign.status = CAMPAIGN_STATUS_ACTIVE;
campaign.total_allocated = 0;
campaign.total_claimed = 0;
campaign.max_supply = max_supply;
campaign.created_at = clock.unix_timestamp;
create_associated_token_account(
payer_info,
campaign_treasury_info,
campaign_treasury_tokens_info,
mint_info,
system_program,
token_program,
associated_token_program,
)?;
if initial_supply > 0 {
transfer_signed(
mint_treasury_info,
mint_treasury_tokens_info,
campaign_treasury_tokens_info,
token_program,
initial_supply,
&[TREASURY, mint.as_ref()], )?;
}
airdrop_api::event::CampaignCreatedEvent {
campaign: *campaign_info.key,
mint: *mint_info.key,
owner: *campaign_owner_info.key,
merkle_root,
initial_supply,
created_at: clock.unix_timestamp,
}
.log();
Ok(())
}