use crate::error::HydraError;
use crate::state::{Fanout, FanoutMembershipVoucher, MembershipModel};
use crate::utils::logic::distribution::{distribute_mint, distribute_native};
use crate::utils::validation::*;
use anchor_lang::prelude::*;
use anchor_spl::token::{Mint, Token, TokenAccount};
#[derive(Accounts)]
#[instruction(distribute_for_mint: bool)]
pub struct DistributeTokenMember<'info> {
pub payer: Signer<'info>,
#[account(mut)]
pub member: UncheckedAccount<'info>,
#[
account(
mut,
constraint = membership_mint_token_account.delegate.is_none(),
constraint = membership_mint_token_account.close_authority.is_none(),
constraint = membership_mint_token_account.mint == membership_mint.key(),
constraint = membership_mint_token_account.owner == member.key()
)]
pub membership_mint_token_account: Account<'info, TokenAccount>,
#[account(
mut,
seeds = [b"fanout-membership", fanout.key().as_ref(), member.key().as_ref()],
constraint = membership_voucher.membership_key == member.key(),
bump = membership_voucher.bump_seed,
)]
pub membership_voucher: Box<Account<'info, FanoutMembershipVoucher>>,
#[account(
mut,
seeds = [b"fanout-config", fanout.name.as_bytes()],
bump = fanout.bump_seed,
)]
pub fanout: Box<Account<'info, Fanout>>,
#[account(mut)]
pub holding_account: UncheckedAccount<'info>,
#[account(mut)]
pub fanout_for_mint: UncheckedAccount<'info>,
#[account(mut)]
pub fanout_for_mint_membership_voucher: UncheckedAccount<'info>,
pub fanout_mint: Account<'info, Mint>,
#[account(mut)]
pub fanout_mint_member_token_account: UncheckedAccount<'info>,
pub system_program: Program<'info, System>,
pub rent: Sysvar<'info, Rent>,
pub token_program: Program<'info, Token>,
#[account(
mut,
constraint = fanout.membership_mint.is_some() && membership_mint.key() == fanout.membership_mint.unwrap(),
)]
pub membership_mint: Account<'info, Mint>,
#[account(
mut,
constraint = member_stake_account.owner == membership_voucher.key(),
constraint = member_stake_account.mint == membership_mint.key(),
constraint = member_stake_account.amount > 0
)]
pub member_stake_account: Account<'info, TokenAccount>,
}
pub fn distribute_for_token(
ctx: Context<DistributeTokenMember>,
distribute_for_mint: bool,
) -> Result<()> {
let fanout = &mut ctx.accounts.fanout;
let fanout_info = fanout.to_account_info();
let membership_voucher = &mut ctx.accounts.membership_voucher;
let membership_voucher_info = membership_voucher.to_account_info();
let member = &mut ctx.accounts.member;
let membership_mint = &ctx.accounts.membership_mint;
fanout.total_shares = membership_mint.supply;
assert_ata(
&ctx.accounts.member_stake_account.to_account_info(),
&membership_voucher.key(),
&membership_mint.key(),
Some(HydraError::InvalidStakeAta.into()),
)?;
assert_owned_by(&fanout_info, &crate::ID)?;
assert_owned_by(&membership_voucher_info, &crate::ID)?;
assert_owned_by(&member.to_account_info(), &System::id())?;
assert_membership_model(fanout, MembershipModel::Token)?;
assert_shares_distributed(fanout)?;
if distribute_for_mint {
distribute_mint(
ctx.accounts.fanout_mint.to_owned(),
&mut ctx.accounts.fanout_for_mint,
&mut ctx.accounts.fanout_for_mint_membership_voucher,
&mut ctx.accounts.fanout_mint_member_token_account,
&mut ctx.accounts.holding_account,
fanout,
&mut ctx.accounts.membership_voucher,
ctx.accounts.rent.to_owned(),
ctx.accounts.system_program.to_owned(),
ctx.accounts.token_program.to_owned(),
ctx.accounts.payer.to_account_info(),
ctx.accounts.member.to_owned(),
&ctx.accounts.member.key(),
)?;
} else {
distribute_native(
&mut ctx.accounts.holding_account,
&mut ctx.accounts.fanout,
&mut ctx.accounts.membership_voucher,
ctx.accounts.member.to_owned(),
ctx.accounts.rent.to_owned(),
)?;
}
Ok(())
}