1pub mod logic;
2pub mod validation;
3
4use crate::error::HydraError;
5use crate::state::{FanoutMembershipMintVoucher, FanoutMint, FANOUT_MINT_MEMBERSHIP_VOUCHER_SIZE};
6use crate::utils::validation::{assert_derivation, assert_owned_by};
7use anchor_lang::prelude::*;
8use anchor_lang::solana_program::program::invoke_signed;
9use anchor_lang::solana_program::system_instruction;
10use anchor_spl::token::TokenAccount;
11use std::convert::TryInto;
12
13pub fn create_or_allocate_account_raw<'a>(
14 program_id: Pubkey,
15 new_account_info: &AccountInfo<'a>,
16 rent_sysvar_info: &AccountInfo<'a>,
17 system_program_info: &AccountInfo<'a>,
18 payer_info: &AccountInfo<'a>,
19 size: usize,
20 signer_seeds: &[&[u8]],
21 new_acct_seeds: &[&[u8]],
22) -> Result<()> {
23 let rent = &Rent::from_account_info(rent_sysvar_info)?;
24 let required_lamports = rent
25 .minimum_balance(size)
26 .max(1)
27 .saturating_sub(new_account_info.lamports());
28 if required_lamports > 0 {
29 let seeds: &[&[&[u8]]];
30 let as_arr = [signer_seeds];
31
32 if signer_seeds.len() > 0 {
33 seeds = &as_arr;
34 } else {
35 seeds = &[];
36 }
37 invoke_signed(
38 &system_instruction::transfer(&payer_info.key, new_account_info.key, required_lamports),
39 &[
40 payer_info.clone(),
41 new_account_info.clone(),
42 system_program_info.clone(),
43 ],
44 seeds,
45 )?;
46 }
47 let accounts = &[new_account_info.clone(), system_program_info.clone()];
48 invoke_signed(
49 &system_instruction::allocate(new_account_info.key, size.try_into().unwrap()),
50 accounts,
51 &[&new_acct_seeds],
52 )?;
53 invoke_signed(
54 &system_instruction::assign(new_account_info.key, &program_id),
55 accounts,
56 &[&new_acct_seeds],
57 )?;
58 Ok(())
59}
60
61pub fn parse_fanout_mint(
62 fanout_for_mint: &mut UncheckedAccount,
63 fanout: &Pubkey,
64 fanout_mint: &Pubkey,
65) -> Result<FanoutMint> {
66 let account_info = fanout_for_mint.to_account_info();
67 let fanout_mint_bump = assert_derivation(
68 &crate::ID,
69 &account_info,
70 &[b"fanout-config", fanout.as_ref(), fanout_mint.as_ref()],
71 Some(HydraError::InvalidFanoutForMint.into()),
72 )?;
73 let fanout_mint_data: &mut [u8] = &mut fanout_for_mint.try_borrow_mut_data()?;
74 let fanout_for_mint_object: FanoutMint =
75 FanoutMint::try_deserialize(&mut fanout_mint_data.as_ref())?;
76 if fanout_mint_bump != fanout_for_mint_object.bump_seed {
77 msg!("Invalid Fanout For Mint");
78 return Err(HydraError::InvalidFanoutForMint.into());
79 }
80 Ok(fanout_for_mint_object)
81}
82
83pub fn parse_token_account(
84 account: &AccountInfo,
85 owner: &Pubkey,
86) -> Result<TokenAccount> {
87 let ref_data = account.try_borrow_data()?;
88 let mut account_data: &[u8] = &ref_data;
89 let account_object = TokenAccount::try_deserialize(&mut account_data)?;
90 if &account_object.owner != owner {
91 msg!("Token Account has wrong owner");
92 return Err(HydraError::IncorrectOwner.into());
93 }
94 Ok(account_object)
95}
96
97pub fn parse_mint_membership_voucher<'info>(
98 fanout_for_mint_membership_voucher: &mut UncheckedAccount<'info>,
99 rent: &Sysvar<'info, anchor_lang::prelude::Rent>,
100 system_program: &Program<'info, System>,
101 payer: &anchor_lang::prelude::AccountInfo<'info>,
102 membership_key: &Pubkey,
103 fanout_for_mint: &Pubkey,
104 fanout_mint: &Pubkey,
105 fanout: &Pubkey,
106) -> Result<FanoutMembershipMintVoucher> {
107 let account_info = fanout_for_mint_membership_voucher.to_account_info();
108 let mint_membership_voucher_bump = assert_derivation(
109 &crate::ID,
110 &account_info,
111 &[
112 b"fanout-membership",
113 fanout_for_mint.as_ref(),
114 membership_key.as_ref(),
115 fanout_mint.as_ref(),
116 ],
117 Some(HydraError::InvalidMembershipVoucher.into()),
118 )?;
119 let mint_voucher_empty = fanout_for_mint_membership_voucher.data_is_empty();
120
121 Ok(if mint_voucher_empty {
122 create_or_allocate_account_raw(
123 crate::ID,
124 &account_info,
125 &rent.to_account_info(),
126 &system_program,
127 payer,
128 FANOUT_MINT_MEMBERSHIP_VOUCHER_SIZE,
129 &[],
130 &[
131 b"fanout-membership",
132 &fanout_for_mint.as_ref(),
133 &membership_key.as_ref(),
134 &fanout_mint.as_ref(),
135 &[mint_membership_voucher_bump],
136 ],
137 )?;
138 FanoutMembershipMintVoucher {
139 fanout: *fanout,
140 fanout_mint: *fanout_mint,
141 last_inflow: 0,
142 bump_seed: mint_membership_voucher_bump,
143 }
144 } else {
145 let mut membership_data: &[u8] =
146 &fanout_for_mint_membership_voucher.try_borrow_mut_data()?;
147 assert_owned_by(&fanout_for_mint_membership_voucher, &crate::ID)?;
148 let membership = FanoutMembershipMintVoucher::try_deserialize(&mut membership_data)?;
149 if membership.bump_seed != mint_membership_voucher_bump {
150 msg!("Mint Membership Bump Doesnt match");
151 return Err(HydraError::InvalidMembershipVoucher.into());
152 }
153 membership
154 })
155}