sablier_network_program/jobs/take_snapshot/
create_frame.rs1use anchor_lang::{prelude::*, solana_program::instruction::Instruction, InstructionData};
2use anchor_spl::{associated_token::get_associated_token_address, token::TokenAccount};
3use sablier_utils::thread::{ThreadResponse, PAYER_PUBKEY};
4
5use crate::{constants::*, state::*};
6
7#[derive(Accounts)]
8pub struct TakeSnapshotCreateFrame<'info> {
9 #[account(address = Config::pubkey())]
10 pub config: AccountLoader<'info, Config>,
11
12 #[account(mut)]
13 pub payer: Signer<'info>,
14
15 #[account(
16 address = Registry::pubkey(),
17 constraint = registry.locked
18 )]
19 pub registry: Account<'info, Registry>,
20
21 #[account(
22 mut,
23 seeds = [
24 SEED_SNAPSHOT,
25 snapshot.id.to_be_bytes().as_ref(),
26 ],
27 bump,
28 constraint = (registry.current_epoch + 1) == snapshot.id,
29 constraint = snapshot.total_frames < registry.total_workers,
30 )]
31 pub snapshot: Account<'info, Snapshot>,
32
33 #[account(
34 init,
35 seeds = [
36 SEED_SNAPSHOT_FRAME,
37 snapshot.key().as_ref(),
38 snapshot.total_frames.to_be_bytes().as_ref(),
39 ],
40 bump,
41 payer = payer,
42 space = 8 + SnapshotFrame::INIT_SPACE,
43 )]
44 pub snapshot_frame: Account<'info, SnapshotFrame>,
45
46 pub system_program: Program<'info, System>,
47
48 #[account(address = config.load()?.epoch_thread)]
49 pub thread: Signer<'info>,
50
51 #[account(
52 address = worker.pubkey(),
53 constraint = worker.id == snapshot.total_frames,
54 )]
55 pub worker: Account<'info, Worker>,
56
57 #[account(
58 associated_token::authority = worker,
59 associated_token::mint = config.load()?.mint,
60 )]
61 pub worker_stake: Account<'info, TokenAccount>,
62}
63
64pub fn handler(ctx: Context<TakeSnapshotCreateFrame>) -> Result<ThreadResponse> {
65 let config_key = ctx.accounts.config.key();
67 let config = &ctx.accounts.config.load()?;
68 let registry = &ctx.accounts.registry;
69 let snapshot = &mut ctx.accounts.snapshot;
70 let snapshot_frame = &mut ctx.accounts.snapshot_frame;
71 let system_program = &ctx.accounts.system_program;
72 let thread = &ctx.accounts.thread;
73 let worker = &ctx.accounts.worker;
74 let worker_stake = &ctx.accounts.worker_stake;
75
76 snapshot_frame.init(
78 snapshot.total_frames,
79 snapshot.key(),
80 worker_stake.amount,
81 snapshot.total_stake,
82 worker.key(),
83 )?;
84
85 snapshot.total_stake += worker_stake.amount;
87 snapshot.total_frames += 1;
88
89 let dynamic_instruction = if worker.total_delegations > 0 {
91 let zeroth_delegation_pubkey = Delegation::pubkey(worker.pubkey(), 0);
93 let zeroth_snapshot_entry_pubkey = SnapshotEntry::pubkey(snapshot_frame.key(), 0);
94 Some(
95 Instruction {
96 program_id: crate::ID,
97 accounts: crate::accounts::TakeSnapshotCreateEntry {
98 config: config_key,
99 delegation: zeroth_delegation_pubkey,
100 payer: PAYER_PUBKEY,
101 registry: registry.key(),
102 snapshot: snapshot.key(),
103 snapshot_entry: zeroth_snapshot_entry_pubkey,
104 snapshot_frame: snapshot_frame.key(),
105 system_program: system_program.key(),
106 thread: thread.key(),
107 worker: worker.key(),
108 }
109 .to_account_metas(Some(true)),
110 data: crate::instruction::TakeSnapshotCreateEntry {}.data(),
111 }
112 .into(),
113 )
114 } else if snapshot.total_frames.lt(®istry.total_workers) {
115 let next_snapshot_frame_pubkey =
117 SnapshotFrame::pubkey(snapshot.key(), snapshot_frame.id + 1);
118 let next_worker_pubkey = Worker::pubkey(worker.id + 1);
119 Some(
120 Instruction {
121 program_id: crate::ID,
122 accounts: crate::accounts::TakeSnapshotCreateFrame {
123 config: config_key,
124 payer: PAYER_PUBKEY,
125 registry: registry.key(),
126 snapshot: snapshot.key(),
127 snapshot_frame: next_snapshot_frame_pubkey,
128 system_program: system_program.key(),
129 thread: thread.key(),
130 worker: next_worker_pubkey,
131 worker_stake: get_associated_token_address(&next_worker_pubkey, &config.mint),
132 }
133 .to_account_metas(Some(true)),
134 data: crate::instruction::TakeSnapshotCreateFrame {}.data(),
135 }
136 .into(),
137 )
138 } else {
139 None
140 };
141
142 Ok(ThreadResponse {
143 dynamic_instruction,
144 close_to: None,
145 trigger: None,
146 })
147}