Skip to main content

antegen_thread_program/instructions/
fiber_create.rs

1use crate::{errors::*, *};
2use anchor_lang::prelude::*;
3use antegen_fiber_program::state::SerializableInstruction;
4
5/// Accounts required by the `fiber_create` instruction.
6/// Validates authority, pre-funds fiber from thread, CPIs to Fiber Program to create,
7/// updates thread fiber tracking.
8#[derive(Accounts)]
9#[instruction(fiber_index: u8)]
10pub struct FiberCreate<'info> {
11    /// The authority of the thread or the thread itself
12    #[account(
13        constraint = authority.key().eq(&thread.authority) || authority.key().eq(&thread.key())
14    )]
15    pub authority: Signer<'info>,
16
17    /// The thread to add the fiber to
18    #[account(
19        mut,
20        seeds = [
21            SEED_THREAD,
22            thread.authority.as_ref(),
23            thread.id.as_slice(),
24        ],
25        bump = thread.bump,
26    )]
27    pub thread: Account<'info, Thread>,
28
29    /// CHECK: Initialized by Fiber Program via CPI
30    #[account(mut)]
31    pub fiber: UncheckedAccount<'info>,
32
33    /// The Fiber Program for CPI
34    pub fiber_program: Program<'info, antegen_fiber_program::program::AntegenFiber>,
35
36    #[account(address = anchor_lang::system_program::ID)]
37    pub system_program: Program<'info, System>,
38}
39
40pub fn fiber_create(
41    ctx: Context<FiberCreate>,
42    fiber_index: u8,
43    instruction: SerializableInstruction,
44    priority_fee: u64,
45    lookup_tables: Vec<Pubkey>,
46) -> Result<()> {
47    let thread = &mut ctx.accounts.thread;
48
49    // Prevent thread_delete instructions in fibers
50    if instruction.program_id.eq(&crate::ID)
51        && instruction.data.len().ge(&8)
52        && instruction.data[..8].eq(crate::instruction::DeleteThread::DISCRIMINATOR)
53    {
54        return Err(AntegenThreadError::InvalidInstruction.into());
55    }
56
57    // Conditional pre-funding: only pre-fund if fiber account is not yet initialized
58    if ctx.accounts.fiber.to_account_info().data_len() == 0 {
59        let space = 8 + antegen_fiber_program::state::FiberVersionedState::INIT_SPACE;
60        let rent_lamports = Rent::get()?.minimum_balance(space);
61        **thread.to_account_info().try_borrow_mut_lamports()? -= rent_lamports;
62        **ctx
63            .accounts
64            .fiber
65            .to_account_info()
66            .try_borrow_mut_lamports()? += rent_lamports;
67    }
68
69    thread.sign(|seeds| {
70        antegen_fiber_program::cpi::create(
71            CpiContext::new_with_signer(
72                ctx.accounts.fiber_program.key(),
73                antegen_fiber_program::cpi::accounts::Create {
74                    thread: thread.to_account_info(),
75                    fiber: ctx.accounts.fiber.to_account_info(),
76                    system_program: ctx.accounts.system_program.to_account_info(),
77                },
78                &[seeds],
79            ),
80            fiber_index,
81            instruction,
82            priority_fee,
83            lookup_tables.clone(),
84        )
85    })?;
86
87    // Track fiber: push to fiber_ids if not present, bump fiber_next_id if needed
88    if !thread.fiber_ids.contains(&fiber_index) {
89        thread.fiber_ids.push(fiber_index);
90        thread.fiber_ids.sort();
91    }
92    if fiber_index >= thread.fiber_next_id {
93        thread.fiber_next_id = fiber_index.saturating_add(1);
94    }
95
96    Ok(())
97}