Skip to main content

antegen_thread_program/instructions/
fiber_update.rs

1use crate::{errors::*, *};
2use anchor_lang::prelude::*;
3use antegen_fiber_program::{program::AntegenFiber, state::SerializableInstruction};
4
5/// Accounts required by the `fiber_update` instruction.
6/// Validates authority, CPIs to Fiber Program to update (or init) the fiber.
7/// Thread PDA pays for fiber init if needed.
8#[derive(Accounts)]
9#[instruction(fiber_index: u8)]
10pub struct FiberUpdate<'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 the fiber belongs to
18    #[account(
19        mut,
20        seeds = [SEED_THREAD, thread.authority.as_ref(), thread.id.as_slice()],
21        bump = thread.bump,
22    )]
23    pub thread: Account<'info, Thread>,
24
25    /// CHECK: The fiber account to update (may not exist yet, validated by Fiber Program via CPI)
26    #[account(mut)]
27    pub fiber: UncheckedAccount<'info>,
28
29    /// The Fiber Program for CPI
30    pub fiber_program: Program<'info, AntegenFiber>,
31
32    pub system_program: Program<'info, System>,
33}
34
35pub fn fiber_update(
36    ctx: Context<FiberUpdate>,
37    fiber_index: u8,
38    instruction: Option<SerializableInstruction>,
39    priority_fee: Option<u64>,
40    track: bool,
41    lookup_tables: Option<Vec<Pubkey>>,
42) -> Result<()> {
43    // Prevent thread_delete instructions in fibers
44    if let Some(ref ix) = instruction {
45        if ix.program_id.eq(&crate::ID)
46            && ix.data.len().ge(&8)
47            && ix.data[..8].eq(crate::instruction::DeleteThread::DISCRIMINATOR)
48        {
49            return Err(AntegenThreadError::InvalidInstruction.into());
50        }
51    }
52
53    let thread = &mut ctx.accounts.thread;
54
55    // Track the fiber in the thread's fiber_ids before CPI
56    if track && !thread.fiber_ids.contains(&fiber_index) {
57        thread.fiber_ids.push(fiber_index);
58        thread.fiber_ids.sort();
59        if fiber_index.ge(&thread.fiber_next_id) {
60            thread.fiber_next_id = fiber_index.saturating_add(1);
61        }
62    }
63
64    // Pre-fund fiber account from thread PDA if not yet initialized
65    let fiber_info = ctx.accounts.fiber.to_account_info();
66    if fiber_info.data_len().eq(&0) {
67        let space = 8 + antegen_fiber_program::state::FiberVersionedState::INIT_SPACE;
68        let rent_lamports = Rent::get()?.minimum_balance(space);
69        **thread.to_account_info().try_borrow_mut_lamports()? -= rent_lamports;
70        **fiber_info.try_borrow_mut_lamports()? += rent_lamports;
71    }
72
73    // CPI to Fiber Program's update_fiber
74    thread.sign(|signer| {
75        antegen_fiber_program::cpi::update(
76            CpiContext::new_with_signer(
77                ctx.accounts.fiber_program.key(),
78                antegen_fiber_program::cpi::accounts::Update {
79                    thread: thread.to_account_info(),
80                    fiber: ctx.accounts.fiber.to_account_info(),
81                    system_program: ctx.accounts.system_program.to_account_info(),
82                },
83                &[signer],
84            ),
85            fiber_index,
86            instruction,
87            priority_fee,
88            lookup_tables.clone(),
89        )
90    })?;
91
92    Ok(())
93}