cronos_network/instructions/
rotator_turn.rs1use cronos_pool::cpi::accounts::Rotate;
2
3use crate::errors::CronosError;
4
5use {crate::state::*, anchor_lang::{prelude::*, solana_program::sysvar}};
6
7#[derive(Accounts)]
8pub struct RotatorTurn<'info> {
9 #[account(
10 address = sysvar::clock::ID,
11 constraint = clock.slot >= rotator.last_slot.checked_add(config.slots_per_rotation).unwrap()
12 )]
13 pub clock: Sysvar<'info, Clock>,
14
15 #[account(seeds = [SEED_CONFIG], bump)]
16 pub config: Account<'info, Config>,
17
18 #[account(
19 seeds = [
20 SEED_SNAPSHOT_ENTRY,
21 entry.snapshot.as_ref(),
22 entry.id.to_be_bytes().as_ref(),
23 ],
24 bump,
25 has_one = snapshot,
26 constraint = is_valid_entry(&entry, &rotator, &snapshot).unwrap() @ CronosError::InvalidSnapshotEntry,
27 )]
28 pub entry: Account<'info, SnapshotEntry>,
29
30 #[account(mut, address = cronos_pool::state::Pool::pda().0)]
31 pub pool: Account<'info, cronos_pool::state::Pool>,
32
33 #[account(address = cronos_pool::state::Config::pda().0)]
34 pub pool_config: Account<'info, cronos_pool::state::Config>,
35
36 #[account(address = cronos_pool::ID)]
37 pub pool_program: Program<'info, cronos_pool::program::CronosPool>,
38
39 #[account(mut, seeds = [SEED_ROTATOR], bump)]
40 pub rotator: Account<'info, Rotator>,
41
42 #[account()]
43 pub signer: Signer<'info>,
44
45 #[account(
46 seeds = [
47 SEED_SNAPSHOT,
48 snapshot.id.to_be_bytes().as_ref()
49 ],
50 bump,
51 constraint = snapshot.status == SnapshotStatus::Current @ CronosError::SnapshotNotCurrent
52 )]
53 pub snapshot: Account<'info, Snapshot>,
54}
55
56pub fn handler(ctx: Context<RotatorTurn>) -> Result<()> {
57 let clock = &ctx.accounts.clock;
59 let entry = &ctx.accounts.entry;
60 let pool = &mut ctx.accounts.pool;
61 let pool_config = &ctx.accounts.pool_config;
62 let pool_program = &ctx.accounts.pool_program;
63 let rotator = &mut ctx.accounts.rotator;
64
65 let rotator_bump = *ctx.bumps.get("rotator").unwrap();
69 cronos_pool::cpi::rotate(
70 CpiContext::new_with_signer(
71 pool_program.to_account_info(),
72 Rotate {
73 config: pool_config.to_account_info(),
74 rotator: rotator.to_account_info(),
75 pool: pool.to_account_info(),
76 },
77 &[&[SEED_ROTATOR, &[rotator_bump]]],
78 ),
79 entry.delegate,
80 )?;
81
82 rotator.hash_nonce(clock.slot)?;
84
85 Ok(())
86}
87
88fn is_valid_entry(
89 entry: &Account<SnapshotEntry>,
90 rotator: &Account<Rotator>,
91 snapshot: &Account<Snapshot>,
92) -> Result<bool> {
93 match rotator.nonce.checked_rem(snapshot.stake_total) {
95 None => Ok(false),
96 Some(sample) => Ok(sample >= entry.stake_offset
97 && sample < entry.stake_offset.checked_add(entry.stake_amount).unwrap()),
98 }
99}