hydra/processors/distribute/
token_member.rs

1use crate::error::HydraError;
2
3use crate::state::{Fanout, FanoutMembershipVoucher, MembershipModel};
4
5use crate::utils::logic::distribution::{distribute_mint, distribute_native};
6
7use crate::utils::validation::*;
8
9use anchor_lang::prelude::*;
10use anchor_spl::token::{Mint, Token, TokenAccount};
11
12#[derive(Accounts)]
13#[instruction(distribute_for_mint: bool)]
14pub struct DistributeTokenMember<'info> {
15    pub payer: Signer<'info>,
16    #[account(mut)]
17    /// CHECK: Optional Account
18    pub member: UncheckedAccount<'info>,
19    #[
20    account(
21    mut,
22    constraint = membership_mint_token_account.delegate.is_none(),
23    constraint = membership_mint_token_account.close_authority.is_none(),
24    constraint = membership_mint_token_account.mint == membership_mint.key(),
25    constraint = membership_mint_token_account.owner == member.key()
26    )]
27    pub membership_mint_token_account: Account<'info, TokenAccount>,
28    #[account(
29    mut,
30    seeds = [b"fanout-membership", fanout.key().as_ref(), member.key().as_ref()],
31    constraint = membership_voucher.membership_key == member.key(),
32    bump = membership_voucher.bump_seed,
33    )]
34    pub membership_voucher: Box<Account<'info, FanoutMembershipVoucher>>,
35    #[account(
36    mut,
37    seeds = [b"fanout-config", fanout.name.as_bytes()],
38    bump = fanout.bump_seed,
39    )]
40    pub fanout: Box<Account<'info, Fanout>>,
41    #[account(mut)]
42    /// CHECK: Could be native or Token Account
43    pub holding_account: UncheckedAccount<'info>,
44    #[account(mut)]
45    /// CHECK: Optional Account
46    pub fanout_for_mint: UncheckedAccount<'info>,
47    #[account(mut)]
48    /// CHECK: Optional Account
49    pub fanout_for_mint_membership_voucher: UncheckedAccount<'info>,
50    pub fanout_mint: Account<'info, Mint>,
51    #[account(mut)]
52    /// CHECK: Optional Account
53    pub fanout_mint_member_token_account: UncheckedAccount<'info>,
54    pub system_program: Program<'info, System>,
55    pub rent: Sysvar<'info, Rent>,
56    pub token_program: Program<'info, Token>,
57    #[account(
58    mut,
59    constraint = fanout.membership_mint.is_some() && membership_mint.key() == fanout.membership_mint.unwrap(),
60    )]
61    pub membership_mint: Account<'info, Mint>,
62    #[account(
63    mut,
64    constraint = member_stake_account.owner == membership_voucher.key(),
65    constraint = member_stake_account.mint == membership_mint.key(),
66    constraint = member_stake_account.amount > 0
67    )]
68    pub member_stake_account: Account<'info, TokenAccount>,
69}
70
71pub fn distribute_for_token(
72    ctx: Context<DistributeTokenMember>,
73    distribute_for_mint: bool,
74) -> Result<()> {
75    let fanout = &mut ctx.accounts.fanout;
76    let fanout_info = fanout.to_account_info();
77    let membership_voucher = &mut ctx.accounts.membership_voucher;
78    let membership_voucher_info = membership_voucher.to_account_info();
79    let member = &mut ctx.accounts.member;
80    let membership_mint = &ctx.accounts.membership_mint;
81    fanout.total_shares = membership_mint.supply;
82    assert_ata(
83        &ctx.accounts.member_stake_account.to_account_info(),
84        &membership_voucher.key(),
85        &membership_mint.key(),
86        Some(HydraError::InvalidStakeAta.into()),
87    )?;
88    assert_owned_by(&fanout_info, &crate::ID)?;
89    assert_owned_by(&membership_voucher_info, &crate::ID)?;
90    assert_owned_by(&member.to_account_info(), &System::id())?;
91    assert_membership_model(fanout, MembershipModel::Token)?;
92    assert_shares_distributed(fanout)?;
93
94    if distribute_for_mint {
95        distribute_mint(
96            ctx.accounts.fanout_mint.to_owned(),
97            &mut ctx.accounts.fanout_for_mint,
98            &mut ctx.accounts.fanout_for_mint_membership_voucher,
99            &mut ctx.accounts.fanout_mint_member_token_account,
100            &mut ctx.accounts.holding_account,
101            fanout,
102            &mut ctx.accounts.membership_voucher,
103            ctx.accounts.rent.to_owned(),
104            ctx.accounts.system_program.to_owned(),
105            ctx.accounts.token_program.to_owned(),
106            ctx.accounts.payer.to_account_info(),
107            ctx.accounts.member.to_owned(),
108            &ctx.accounts.member.key(),
109        )?;
110    } else {
111        distribute_native(
112            &mut ctx.accounts.holding_account,
113            &mut ctx.accounts.fanout,
114            &mut ctx.accounts.membership_voucher,
115            ctx.accounts.member.to_owned(),
116            ctx.accounts.rent.to_owned(),
117        )?;
118    }
119    Ok(())
120}