hydra/processors/stake/
set.rs

1use crate::error::{HydraError, OrArithError};
2use crate::state::{Fanout, FanoutMembershipVoucher, FANOUT_MEMBERSHIP_VOUCHER_SIZE};
3
4use crate::utils::validation::*;
5use crate::MembershipModel;
6use anchor_lang::prelude::*;
7use anchor_spl::token::{Mint, Token, TokenAccount};
8#[derive(Accounts)]
9#[instruction(shares: u64)]
10pub struct SetTokenMemberStake<'info> {
11    #[account(mut)]
12    pub member: Signer<'info>,
13    #[account(
14    mut,
15    seeds = [b"fanout-config", fanout.name.as_bytes()],
16    bump = fanout.bump_seed,
17    )]
18    pub fanout: Account<'info, Fanout>,
19    #[account(
20    init,
21    space = FANOUT_MEMBERSHIP_VOUCHER_SIZE,
22    seeds = [b"fanout-membership", fanout.key().as_ref(), member.key().as_ref()],
23    bump,
24    payer = member
25    )]
26    pub membership_voucher: Account<'info, FanoutMembershipVoucher>,
27    #[account(
28    mut,
29    constraint = fanout.membership_mint.is_some() && membership_mint.key() == fanout.membership_mint.unwrap(),
30    )]
31    pub membership_mint: Account<'info, Mint>,
32    #[account(
33    mut,
34    constraint = membership_mint_token_account.mint == membership_mint.key(),
35    constraint = membership_mint_token_account.delegate.is_none(),
36    constraint = membership_mint_token_account.close_authority.is_none(),
37    constraint = membership_mint_token_account.amount >= shares,
38    constraint = membership_mint_token_account.owner == member.key()
39    )]
40    pub membership_mint_token_account: Account<'info, TokenAccount>,
41    #[account(
42    mut,
43    constraint = member_stake_account.owner == membership_voucher.key(),
44    constraint = member_stake_account.mint == membership_mint.key(),
45    )]
46    pub member_stake_account: Account<'info, TokenAccount>,
47    pub system_program: Program<'info, System>,
48    pub token_program: Program<'info, Token>,
49}
50
51pub fn set_token_member_stake(ctx: Context<SetTokenMemberStake>, shares: u64) -> Result<()> {
52    let fanout = &mut ctx.accounts.fanout;
53    let member = &ctx.accounts.member;
54    let membership_voucher = &mut ctx.accounts.membership_voucher;
55    let membership_mint = &mut ctx.accounts.membership_mint;
56    assert_owned_by(&fanout.to_account_info(), &crate::ID)?;
57    assert_owned_by(&member.to_account_info(), &System::id())?;
58    assert_membership_model(fanout, MembershipModel::Token)?;
59    assert_ata(
60        &ctx.accounts.member_stake_account.to_account_info(),
61        &membership_voucher.key(),
62        &membership_mint.key(),
63        Some(HydraError::InvalidStakeAta.into()),
64    )?;
65    membership_voucher.fanout = fanout.key();
66    membership_voucher.membership_key = member.key();
67    fanout.total_staked_shares = fanout
68        .total_staked_shares
69        .and_then(|ss| ss.checked_add(shares));
70    fanout.total_shares = membership_mint.supply;
71    fanout.total_members = fanout.total_members.checked_add(1).or_arith_error()?;
72    membership_voucher.shares = shares;
73    membership_voucher.bump_seed = *ctx.bumps.get("membership_voucher").unwrap();
74    let cpi_program = ctx.accounts.token_program.to_account_info();
75    let accounts = anchor_spl::token::Transfer {
76        from: ctx.accounts.membership_mint_token_account.to_account_info(),
77        to: ctx.accounts.member_stake_account.to_account_info(),
78        authority: member.to_account_info(),
79    };
80    let cpi_ctx = CpiContext::new(cpi_program, accounts);
81    anchor_spl::token::transfer(cpi_ctx, shares)?;
82    Ok(())
83}