Skip to main content

antegen_thread_program/
lib.rs

1pub mod constants;
2pub mod errors;
3pub mod instructions;
4pub mod state;
5pub mod utils;
6
7/// Fiber program re-exports for direct CPI access.
8/// Use when your program is executed via `thread_exec` and needs to
9/// manage fibers directly (cannot CPI back to thread program due to reentrancy).
10pub mod fiber {
11    pub use antegen_fiber_program::cpi;
12    pub use antegen_fiber_program::program::AntegenFiber;
13    pub use antegen_fiber_program::state::{
14        decompile_instruction, CompiledInstructionV0, Fiber, FiberState, FiberVersionedState,
15    };
16    pub use antegen_fiber_program::ID;
17}
18
19pub use crate::program::AntegenThread;
20pub use constants::*;
21use instructions::*;
22use state::*;
23
24use anchor_lang::prelude::*;
25use state::{SerializableInstruction, Trigger};
26
27declare_id!("AgTv5w1UvUb6zeqkThwMrztGu9hpepBu8YLghuR4dpSx");
28
29#[derive(AnchorSerialize, AnchorDeserialize)]
30pub enum ThreadId {
31    Bytes(Vec<u8>),
32    Pubkey(Pubkey),
33}
34
35impl AsRef<[u8]> for ThreadId {
36    fn as_ref(&self) -> &[u8] {
37        match self {
38            ThreadId::Bytes(bytes) => bytes.as_ref(),
39            ThreadId::Pubkey(pubkey) => pubkey.as_ref(),
40        }
41    }
42}
43
44impl ThreadId {
45    pub fn len(&self) -> usize {
46        match self {
47            ThreadId::Bytes(bytes) => bytes.len(),
48            ThreadId::Pubkey(_) => 32,
49        }
50    }
51
52    pub fn is_empty(&self) -> bool {
53        match self {
54            ThreadId::Bytes(bytes) => bytes.is_empty(),
55            ThreadId::Pubkey(_) => false,
56        }
57    }
58
59    pub fn to_name(&self) -> String {
60        match self {
61            ThreadId::Bytes(bytes) => String::from_utf8_lossy(bytes).to_string(),
62            ThreadId::Pubkey(pubkey) => pubkey.to_string(),
63        }
64    }
65}
66
67impl From<String> for ThreadId {
68    fn from(s: String) -> Self {
69        ThreadId::Bytes(s.into_bytes())
70    }
71}
72
73impl From<&str> for ThreadId {
74    fn from(s: &str) -> Self {
75        ThreadId::Bytes(s.as_bytes().to_vec())
76    }
77}
78
79impl From<Pubkey> for ThreadId {
80    fn from(pubkey: Pubkey) -> Self {
81        ThreadId::Pubkey(pubkey)
82    }
83}
84
85impl From<ThreadId> for Vec<u8> {
86    fn from(id: ThreadId) -> Vec<u8> {
87        match id {
88            ThreadId::Bytes(bytes) => bytes,
89            ThreadId::Pubkey(pubkey) => pubkey.to_bytes().to_vec(),
90        }
91    }
92}
93
94#[program]
95pub mod antegen_thread {
96    use super::*;
97
98    /// Initialize the global thread configuration.
99    pub fn init_config(ctx: Context<ConfigInit>) -> Result<()> {
100        config_init(ctx)
101    }
102
103    /// Update the global thread configuration.
104    pub fn update_config(ctx: Context<ConfigUpdate>, params: ConfigUpdateParams) -> Result<()> {
105        config_update(ctx, params)
106    }
107
108    /// Creates a fiber (instruction) for a thread via CPI to Fiber Program.
109    /// `lookup_tables` is capped at 4 per fiber (Solana v0 transaction limit).
110    pub fn create_fiber(
111        ctx: Context<FiberCreate>,
112        fiber_index: u8,
113        instruction: SerializableInstruction,
114        priority_fee: u64,
115        lookup_tables: Vec<Pubkey>,
116    ) -> Result<()> {
117        fiber_create(ctx, fiber_index, instruction, priority_fee, lookup_tables)
118    }
119
120    /// Closes a fiber from a thread via CPI to Fiber Program.
121    pub fn close_fiber(ctx: Context<FiberClose>, fiber_index: u8) -> Result<()> {
122        fiber_close(ctx, fiber_index)
123    }
124
125    /// Updates a fiber's instruction via CPI to Fiber Program.
126    /// Initializes the fiber if it doesn't exist (thread PDA pays rent).
127    /// If `track` is true, adds the fiber_index to thread.fiber_ids.
128    /// Pass `None` for `instruction` to wipe the compiled instruction (idle).
129    /// Pass `None` for `lookup_tables` to leave them unchanged; `Some(vec)`
130    /// atomically replaces. Legacy fibers reject non-empty lookup_tables.
131    pub fn update_fiber(
132        ctx: Context<FiberUpdate>,
133        fiber_index: u8,
134        instruction: Option<SerializableInstruction>,
135        priority_fee: Option<u64>,
136        track: bool,
137        lookup_tables: Option<Vec<Pubkey>>,
138    ) -> Result<()> {
139        fiber_update(
140            ctx,
141            fiber_index,
142            instruction,
143            priority_fee,
144            track,
145            lookup_tables,
146        )
147    }
148
149    /// Swaps source fiber's instruction into target fiber, closes source.
150    /// Target keeps its PDA/index, source is deleted.
151    pub fn swap_fiber(ctx: Context<FiberSwap>, source_fiber_index: u8) -> Result<()> {
152        instructions::fiber_swap::fiber_swap(ctx, source_fiber_index)
153    }
154
155    /// Creates a new transaction thread.
156    /// Optionally creates fiber index 0 if `instruction` is provided.
157    /// `lookup_tables` is forwarded to fiber_0 when one is created;
158    /// it is ignored when `instruction` is `None`.
159    pub fn create_thread(
160        ctx: Context<ThreadCreate>,
161        amount: u64,
162        id: ThreadId,
163        trigger: Trigger,
164        paused: Option<bool>,
165        instruction: Option<SerializableInstruction>,
166        priority_fee: Option<u64>,
167        lookup_tables: Vec<Pubkey>,
168    ) -> Result<()> {
169        thread_create(
170            ctx,
171            amount,
172            id,
173            trigger,
174            paused,
175            instruction,
176            priority_fee,
177            lookup_tables,
178        )
179    }
180
181    /// Closes an existing thread account and returns the lamports to the owner.
182    /// Requires authority (owner) or thread itself to sign.
183    /// External fiber accounts should be passed via remaining_accounts.
184    pub fn close_thread<'info>(ctx: Context<'info, ThreadClose<'info>>) -> Result<()> {
185        thread_close(ctx)
186    }
187
188    /// Executes a thread fiber with trigger validation and fee distribution.
189    /// Respects builder claim priority windows from registry configuration.
190    pub fn exec_thread<'info>(
191        ctx: Context<'info, ThreadExec<'info>>,
192        forgo_commission: bool,
193        fiber_cursor: u8,
194    ) -> Result<()> {
195        thread_exec(ctx, forgo_commission, fiber_cursor)
196    }
197
198    /// Allows an owner to update the thread's properties (paused state, trigger).
199    pub fn update_thread(ctx: Context<ThreadUpdate>, params: ThreadUpdateParams) -> Result<()> {
200        thread_update(ctx, params)
201    }
202
203    /// Allows an owner to withdraw from a thread's lamport balance.
204    pub fn withdraw_thread(ctx: Context<ThreadWithdraw>, amount: u64) -> Result<()> {
205        thread_withdraw(ctx, amount)
206    }
207
208    /// Memo instruction that logs a message (replacement for spl-memo).
209    /// Used for tracking thread fiber execution in logs without external dependencies.
210    /// Optionally emits a signal for testing signal behaviors.
211    pub fn thread_memo(
212        ctx: Context<ThreadMemo>,
213        memo: String,
214        signal: Option<Signal>,
215    ) -> Result<Signal> {
216        instructions::thread_memo::thread_memo(ctx, memo, signal)
217    }
218
219    /// Deletes a thread - admin only, skips all checks.
220    /// Used for cleaning up stuck/broken threads.
221    pub fn delete_thread(ctx: Context<ThreadDelete>) -> Result<()> {
222        thread_delete(ctx)
223    }
224}