tentacles 0.1.1

Client for the tentacles program
Documentation
use anchor_lang::prelude::*;
use anchor_spl::token::{Token, TokenAccount, Mint};
use anchor_spl::associated_token::AssociatedToken;

const MAX_MEMBERS: usize = 5;
const MEMBER_INFO_SIZE: usize = 32 + 8 + 8 + 32; // 80 bytes
const TOTAL_MEMBERS_SPACE: usize = MAX_MEMBERS * MEMBER_INFO_SIZE; // 400 bytes

#[account]
#[derive(Default, Debug)]
pub struct SplitWallet {
    pub authority: Pubkey,
    pub tentacles: Pubkey,
    pub name: String,
    pub mint: Pubkey,
    pub total_shares: u64,
    pub total_members: u8,
    pub last_inflow: u64,
    pub total_inflow: u64,
    pub token_account: Pubkey,
    pub remaining_flow: u64,
    pub bump_seed: u8,
    pub total_available_shares: u64,
    pub disburse_cycles: u64, // Added disburse cycles
    pub members: Vec<MemberInfo>,
}

impl SplitWallet {
    pub fn is_member(&self, member_info: &MemberInfo) -> bool {
        self.members.iter().any(|m| m.member == member_info.member)
    }

    pub fn find_member_index(&self, member_pubkey: &Pubkey) -> Option<usize> {
        self.members.iter().position(|m| m.member == *member_pubkey)
    }
}

#[derive(Clone, AnchorSerialize, AnchorDeserialize, Debug)]
pub struct MemberInfo {
    pub member: Pubkey,
    pub shares: u64,
    pub disburse_cycles: u64,
    pub member_token_account: Pubkey,
}

#[derive(Accounts)]
#[instruction(name: String, bump: u8)]
pub struct InitializeWallet<'info> {
    #[account(
        init,
        payer = authority,
        seeds = [b"split_wallet".as_ref(), name.as_bytes()],
        bump,
        space = 8 + 32 + 32 + 4 + name.len() + 32 + 8 + 1 + 8 + 8 + 32 + 8 + 1 + 8 + TOTAL_MEMBERS_SPACE
    )]
    pub wallet: Account<'info, SplitWallet>,
    #[account(
        mut,
        constraint = wallet_token_account.owner == wallet.key(),
        constraint = wallet_token_account.delegate.is_none(),
        constraint = wallet_token_account.close_authority.is_none(),
        constraint = wallet_token_account.mint == mint.key(),
    )]
    pub wallet_token_account: Account<'info, TokenAccount>,
    pub mint: Account<'info, Mint>,
    #[account(mut)]
    pub authority: Signer<'info>,
    pub system_program: Program<'info, System>,
    pub rent: Sysvar<'info, Rent>,
    pub associated_token_program: Program<'info, AssociatedToken>,
    pub token_program: Program<'info, Token>,
}

#[derive(Accounts)]
pub struct AddMember<'info> {
    #[account(
        mut,
        has_one = authority,
    )]
    pub wallet: Account<'info, SplitWallet>,
    /// CHECK: Checked in program
    pub member: UncheckedAccount<'info>,
    /// CHECK: We will manually check this account in the instruction logic.
    #[account(mut)]
    pub member_token_account: UncheckedAccount<'info>,
    #[account(mut)]
    pub authority: Signer<'info>,
    pub mint: Account<'info, Mint>,
    pub system_program: Program<'info, System>,
    pub rent: Sysvar<'info, Rent>,
    pub associated_token_program: Program<'info, AssociatedToken>,
    pub token_program: Program<'info, Token>,
}

#[derive(Accounts)]
pub struct Distribute<'info> {
    #[account(mut)]
    pub wallet: Account<'info, SplitWallet>,
    pub pda_as_authority: AccountInfo<'info>,
    #[account(mut)]
    pub wallet_token_account: Account<'info, TokenAccount>,
    #[account(mut)]
    pub member_token_account: Account<'info, TokenAccount>,
    #[account(signer)]
    pub wallet_authority: AccountInfo<'info>,
    pub token_program: Program<'info, Token>,
    pub mint: Account<'info, Mint>,
    pub rent: Sysvar<'info, Rent>,
    pub system_program: Program<'info, System>,
    pub associated_token_program: Program<'info, AssociatedToken>,
}