Skip to main content

antegen_thread_program/instructions/
thread_update.rs

1use crate::{state::*, utils::next_timestamp, *};
2use anchor_lang::prelude::*;
3
4/// Parameters for updating a thread
5#[derive(AnchorSerialize, AnchorDeserialize, Default)]
6pub struct ThreadUpdateParams {
7    /// Explicitly set the paused state (not a toggle)
8    pub paused: Option<bool>,
9    /// Update the thread's trigger
10    pub trigger: Option<Trigger>,
11}
12
13/// Accounts required by the `thread_update` instruction.
14#[derive(Accounts)]
15pub struct ThreadUpdate<'info> {
16    /// The authority (owner) of the thread.
17    #[account(mut)]
18    pub authority: Signer<'info>,
19
20    /// The thread to be updated.
21    #[account(
22        mut,
23        constraint = authority.key().eq(&thread.authority),
24        seeds = [
25            SEED_THREAD,
26            thread.authority.as_ref(),
27            thread.id.as_slice(),
28        ],
29        bump = thread.bump,
30    )]
31    pub thread: Account<'info, Thread>,
32}
33
34pub fn thread_update(ctx: Context<ThreadUpdate>, params: ThreadUpdateParams) -> Result<()> {
35    let thread = &mut ctx.accounts.thread;
36
37    // Update paused state if provided (explicit, not toggle)
38    if let Some(paused) = params.paused {
39        thread.paused = paused;
40    }
41
42    // Update the trigger if provided
43    if let Some(trigger) = params.trigger {
44        let clock = Clock::get()?;
45        let current_timestamp = clock.unix_timestamp;
46        let thread_pubkey = thread.key();
47
48        thread.trigger = trigger.clone();
49
50        // Initialize schedule based on trigger type (mirrors thread_create logic)
51        thread.schedule = match &trigger {
52            Trigger::Account { .. } => Schedule::OnChange { prev: 0 },
53            Trigger::Cron {
54                schedule, jitter, ..
55            } => {
56                let base_next =
57                    next_timestamp(current_timestamp, schedule.clone()).unwrap_or(current_timestamp);
58                let jitter_offset =
59                    crate::utils::calculate_jitter_offset(current_timestamp, &thread_pubkey, *jitter);
60                Schedule::Timed {
61                    prev: current_timestamp,
62                    next: base_next.saturating_add(jitter_offset),
63                }
64            }
65            Trigger::Immediate { .. } => Schedule::Timed {
66                prev: current_timestamp,
67                next: current_timestamp,
68            },
69            Trigger::Slot { slot } => Schedule::Block {
70                prev: clock.slot,
71                next: *slot,
72            },
73            Trigger::Epoch { epoch } => Schedule::Block {
74                prev: clock.epoch,
75                next: *epoch,
76            },
77            Trigger::Interval {
78                seconds, jitter, ..
79            } => {
80                let base_next = current_timestamp.saturating_add(*seconds);
81                let jitter_offset =
82                    crate::utils::calculate_jitter_offset(current_timestamp, &thread_pubkey, *jitter);
83                Schedule::Timed {
84                    prev: current_timestamp,
85                    next: base_next.saturating_add(jitter_offset),
86                }
87            }
88            Trigger::Timestamp { unix_ts, .. } => Schedule::Timed {
89                prev: current_timestamp,
90                next: *unix_ts,
91            },
92        };
93    }
94
95    Ok(())
96}