sablier_network_program/jobs/stake_delegations/
process_delegation.rs1use anchor_lang::{prelude::*, solana_program::instruction::Instruction, InstructionData};
2use anchor_spl::{
3 associated_token::get_associated_token_address,
4 token::{transfer, Token, TokenAccount, Transfer},
5};
6use sablier_utils::thread::ThreadResponse;
7
8use crate::{constants::*, state::*};
9
10#[derive(Accounts)]
11pub struct StakeDelegationsProcessDelegation<'info> {
12 #[account(address = Config::pubkey())]
13 pub config: AccountLoader<'info, Config>,
14
15 #[account(
16 mut,
17 seeds = [
18 SEED_DELEGATION,
19 delegation.worker.as_ref(),
20 delegation.id.to_be_bytes().as_ref(),
21 ],
22 bump,
23 has_one = worker
24 )]
25 pub delegation: Account<'info, Delegation>,
26
27 #[account(
28 mut,
29 associated_token::authority = delegation,
30 associated_token::mint = config.load()?.mint,
31 )]
32 pub delegation_stake: Account<'info, TokenAccount>,
33
34 #[account(
35 address = Registry::pubkey(),
36 constraint = registry.locked
37 )]
38 pub registry: Account<'info, Registry>,
39
40 #[account(address = config.load()?.epoch_thread)]
41 pub thread: Signer<'info>,
42
43 pub token_program: Program<'info, Token>,
44
45 #[account(address = worker.pubkey())]
46 pub worker: Account<'info, Worker>,
47
48 #[account(
49 mut,
50 associated_token::authority = worker,
51 associated_token::mint = config.load()?.mint,
52 )]
53 pub worker_stake: Account<'info, TokenAccount>,
54}
55
56pub fn handler(ctx: Context<StakeDelegationsProcessDelegation>) -> Result<ThreadResponse> {
57 let config_key = ctx.accounts.config.key();
59 let config = &ctx.accounts.config.load()?;
60 let delegation = &mut ctx.accounts.delegation;
61 let delegation_stake = &mut ctx.accounts.delegation_stake;
62 let registry = &ctx.accounts.registry;
63 let thread = &ctx.accounts.thread;
64 let token_program = &ctx.accounts.token_program;
65 let worker = &ctx.accounts.worker;
66 let worker_stake = &ctx.accounts.worker_stake;
67
68 let amount = delegation_stake.amount;
70 let bump = ctx.bumps.delegation;
71 transfer(
72 CpiContext::new_with_signer(
73 token_program.to_account_info(),
74 Transfer {
75 from: delegation_stake.to_account_info(),
76 to: worker_stake.to_account_info(),
77 authority: delegation.to_account_info(),
78 },
79 &[&[
80 SEED_DELEGATION,
81 delegation.worker.as_ref(),
82 delegation.id.to_be_bytes().as_ref(),
83 &[bump],
84 ]],
85 ),
86 amount,
87 )?;
88
89 delegation.stake_amount += amount;
91
92 let dynamic_instruction = if (delegation.id + 1) < worker.total_delegations {
94 let next_delegation_pubkey = Delegation::pubkey(worker.key(), delegation.id + 1);
96 Some(
97 Instruction {
98 program_id: crate::ID,
99 accounts: crate::accounts::StakeDelegationsProcessDelegation {
100 config: config_key,
101 delegation: next_delegation_pubkey,
102 delegation_stake: get_associated_token_address(
103 &next_delegation_pubkey,
104 &config.mint,
105 ),
106 registry: registry.key(),
107 thread: thread.key(),
108 token_program: token_program.key(),
109 worker: worker.key(),
110 worker_stake: worker_stake.key(),
111 }
112 .to_account_metas(Some(true)),
113 data: crate::instruction::StakeDelegationsProcessDelegation {}.data(),
114 }
115 .into(),
116 )
117 } else if (worker.id + 1) < registry.total_workers {
118 Some(
120 Instruction {
121 program_id: crate::ID,
122 accounts: crate::accounts::StakeDelegationsProcessWorker {
123 config: config_key,
124 registry: registry.key(),
125 thread: thread.key(),
126 worker: Worker::pubkey(worker.id + 1),
127 }
128 .to_account_metas(Some(true)),
129 data: crate::instruction::StakeDelegationsProcessWorker {}.data(),
130 }
131 .into(),
132 )
133 } else {
134 None
135 };
136
137 Ok(ThreadResponse {
138 dynamic_instruction,
139 close_to: None,
140 trigger: None,
141 })
142}