hydra/processors/init/
init_parent.rs

1use crate::error::HydraError;
2use crate::state::{Fanout, MembershipModel};
3use anchor_lang::prelude::*;
4use anchor_spl::token::{Mint, Token};
5
6#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)]
7pub struct InitializeFanoutArgs {
8    pub bump_seed: u8,
9    pub native_account_bump_seed: u8,
10    pub name: String,
11    pub total_shares: u64,
12}
13
14#[derive(Accounts)]
15#[instruction(args: InitializeFanoutArgs)]
16pub struct InitializeFanout<'info> {
17    #[account(mut)]
18    pub authority: Signer<'info>,
19    #[account(
20    init,
21    space = 300,
22    seeds = [b"fanout-config", args.name.as_bytes()],
23    bump,
24    payer = authority
25    )]
26    pub fanout: Account<'info, Fanout>,
27    #[account(
28    init,
29    space = 1,
30    seeds = [b"fanout-native-account", fanout.key().as_ref()],
31    bump,
32    payer = authority
33    )
34    ]
35    /// CHECK: Native Account
36    pub holding_account: UncheckedAccount<'info>,
37    pub system_program: Program<'info, System>,
38    #[account(mut)]
39    pub membership_mint: Account<'info, Mint>,
40    pub rent: Sysvar<'info, Rent>,
41    pub token_program: Program<'info, Token>,
42}
43pub fn init(
44    ctx: Context<InitializeFanout>,
45    args: InitializeFanoutArgs,
46    model: MembershipModel,
47) -> Result<()> {
48    let membership_mint = &ctx.accounts.membership_mint;
49    let fanout = &mut ctx.accounts.fanout;
50    fanout.authority = ctx.accounts.authority.to_account_info().key();
51    fanout.account_key = ctx.accounts.holding_account.to_account_info().key();
52    fanout.name = args.name;
53    fanout.total_shares = args.total_shares;
54    fanout.total_available_shares = args.total_shares;
55    fanout.total_inflow = 0;
56    fanout.last_snapshot_amount = fanout.total_inflow;
57    fanout.bump_seed = args.bump_seed;
58    fanout.membership_model = model;
59    fanout.membership_mint = if membership_mint.key() == spl_token::native_mint::id() {
60        None
61    } else {
62        Some(membership_mint.key())
63    };
64    match fanout.membership_model {
65        MembershipModel::Wallet | MembershipModel::NFT => {
66            fanout.membership_mint = None;
67            fanout.total_staked_shares = None;
68        }
69        MembershipModel::Token => {
70            fanout.total_shares = membership_mint.supply;
71            fanout.total_available_shares = 0;
72            if fanout.membership_mint.is_none() {
73                return Err(HydraError::MintAccountRequired.into());
74            }
75            let mint = &ctx.accounts.membership_mint;
76            fanout.total_staked_shares = Some(0);
77            if !mint.is_initialized {
78                let cpi_program = ctx.accounts.token_program.to_account_info();
79                let accounts = anchor_spl::token::InitializeMint {
80                    mint: mint.to_account_info(),
81                    rent: ctx.accounts.rent.to_account_info(),
82                };
83                let cpi_ctx = CpiContext::new(cpi_program, accounts);
84                anchor_spl::token::initialize_mint(
85                    cpi_ctx,
86                    0,
87                    &ctx.accounts.authority.to_account_info().key(),
88                    Some(&ctx.accounts.authority.to_account_info().key()),
89                )?;
90            }
91        }
92    };
93
94    Ok(())
95}