sablier_network_program/jobs/delete_snapshot/
process_frame.rs

1use anchor_lang::{prelude::*, solana_program::instruction::Instruction, InstructionData};
2use sablier_utils::thread::ThreadResponse;
3
4use crate::{constants::*, state::*};
5
6#[derive(Accounts)]
7pub struct DeleteSnapshotProcessFrame<'info> {
8    #[account(address = Config::pubkey())]
9    pub config: AccountLoader<'info, Config>,
10
11    #[account(
12        address = Registry::pubkey(),
13        constraint = !registry.locked
14    )]
15    pub registry: Account<'info, Registry>,
16
17    #[account(
18        mut,
19        seeds = [
20            SEED_SNAPSHOT,
21            snapshot.id.to_be_bytes().as_ref(),
22        ],
23        bump,
24        constraint = snapshot.id < registry.current_epoch
25    )]
26    pub snapshot: Account<'info, Snapshot>,
27
28    #[account(
29        mut,
30        seeds = [
31            SEED_SNAPSHOT_FRAME,
32            snapshot_frame.snapshot.as_ref(),
33            snapshot_frame.id.to_be_bytes().as_ref(),
34        ],
35        bump,
36        has_one = snapshot,
37    )]
38    pub snapshot_frame: Account<'info, SnapshotFrame>,
39
40    #[account(
41        mut,
42        address = config.load()?.epoch_thread
43    )]
44    pub thread: Signer<'info>,
45}
46
47pub fn handler(ctx: Context<DeleteSnapshotProcessFrame>) -> Result<ThreadResponse> {
48    // Get accounts
49    let config = &ctx.accounts.config;
50    let registry = &ctx.accounts.registry;
51    let snapshot = &mut ctx.accounts.snapshot;
52    let snapshot_frame = &mut ctx.accounts.snapshot_frame;
53    let thread = &mut ctx.accounts.thread;
54
55    // If this frame has no entries, then close the frame account.
56    if snapshot_frame.total_entries == 0 {
57        let snapshot_frame_lamports = snapshot_frame.get_lamports();
58        snapshot_frame.sub_lamports(snapshot_frame_lamports)?;
59        thread.add_lamports(snapshot_frame_lamports)?;
60
61        // If this is also the last frame in the snapshot, then close the snapshot account.
62        if (snapshot_frame.id + 1) == snapshot.total_frames {
63            let snapshot_lamports = snapshot.get_lamports();
64            snapshot_frame.sub_lamports(snapshot_lamports)?;
65            thread.add_lamports(snapshot_lamports)?;
66        }
67    }
68
69    // Build the next instruction.
70    let dynamic_instruction = if snapshot_frame.total_entries > 0 {
71        // This frame has entries. Delete the entries.
72        Some(
73            Instruction {
74                program_id: crate::ID,
75                accounts: crate::accounts::DeleteSnapshotProcessEntry {
76                    config: config.key(),
77                    registry: registry.key(),
78                    snapshot: snapshot.key(),
79                    snapshot_entry: SnapshotEntry::pubkey(snapshot_frame.key(), 0),
80                    snapshot_frame: snapshot_frame.key(),
81                    thread: thread.key(),
82                }
83                .to_account_metas(Some(true)),
84                data: crate::instruction::DeleteSnapshotProcessEntry {}.data(),
85            }
86            .into(),
87        )
88    } else if (snapshot_frame.id + 1) < snapshot.total_frames {
89        // There are no more entries in this frame. Move on to the next frame.
90        Some(
91            Instruction {
92                program_id: crate::ID,
93                accounts: crate::accounts::DeleteSnapshotProcessFrame {
94                    config: config.key(),
95                    registry: registry.key(),
96                    snapshot: snapshot.key(),
97                    snapshot_frame: SnapshotFrame::pubkey(snapshot.key(), snapshot_frame.id + 1),
98                    thread: thread.key(),
99                }
100                .to_account_metas(Some(true)),
101                data: crate::instruction::DeleteSnapshotProcessFrame {}.data(),
102            }
103            .into(),
104        )
105    } else {
106        // This frame has no entries, and it was the last frame. We are done!
107        None
108    };
109
110    Ok(ThreadResponse {
111        dynamic_instruction,
112        ..ThreadResponse::default()
113    })
114}