switchboard_solana/oracle_program/accounts/queue.rs
1use crate::prelude::*;
2use crate::TOKEN_PID;
3use bytemuck::try_cast_slice_mut;
4use std::cell::Ref;
5
6#[account(zero_copy(unsafe))]
7#[repr(packed)]
8pub struct OracleQueueAccountData {
9 /// Name of the queue to store on-chain.
10 pub name: [u8; 32],
11 /// Metadata of the queue to store on-chain.
12 pub metadata: [u8; 64],
13 /// The account delegated as the authority for making account changes or assigning permissions targeted at the queue.
14 pub authority: Pubkey,
15 /// Interval when stale oracles will be removed if they fail to heartbeat.
16 pub oracle_timeout: u32,
17 /// Rewards to provide oracles and round openers on this queue.
18 pub reward: u64,
19 /// The minimum amount of stake oracles must present to remain on the queue.
20 pub min_stake: u64,
21 /// Whether slashing is enabled on this queue.
22 pub slashing_enabled: bool,
23 /// The tolerated variance amount oracle results can have from the accepted round result before being slashed.
24 /// slashBound = varianceToleranceMultiplier * stdDeviation Default: 2
25 pub variance_tolerance_multiplier: SwitchboardDecimal,
26 /// Number of update rounds new feeds are on probation for.
27 /// If a feed returns 429s within probation period, auto disable permissions.
28 pub feed_probation_period: u32,
29 //
30 /// Current index of the oracle rotation.
31 pub curr_idx: u32,
32 /// Current number of oracles on a queue.
33 pub size: u32,
34 /// Garbage collection index.
35 pub gc_idx: u32,
36 /// Consecutive failure limit for a feed before feed permission is revoked.
37 pub consecutive_feed_failure_limit: u64,
38 /// Consecutive failure limit for an oracle before oracle permission is revoked.
39 pub consecutive_oracle_failure_limit: u64,
40 /// Enabling this setting means data feeds do not need explicit permission to join the queue and request new values from its oracles.
41 pub unpermissioned_feeds_enabled: bool,
42 /// Enabling this setting means VRF accounts do not need explicit permission to join the queue and request new values from its oracles.
43 pub unpermissioned_vrf_enabled: bool,
44 /// TODO: Revenue percentage rewarded to job curators overall.
45 pub curator_reward_cut: SwitchboardDecimal,
46 /// Prevent new leases from being funded n this queue.
47 /// Useful to turn down a queue for migrations, since authority is always immutable.
48 pub lock_lease_funding: bool,
49 /// Token mint used for the oracle queue rewards and slashing.
50 pub mint: Pubkey,
51 /// Whether oracles are permitted to fulfill buffer relayer update request.
52 pub enable_buffer_relayers: bool,
53 /// Reserved for future info.
54 pub _ebuf: [u8; 968],
55 /// Maximum number of oracles a queue can support.
56 pub max_size: u32,
57 /// The public key of the OracleQueueBuffer account holding a collection of Oracle pubkeys that haver successfully heartbeated before the queues `oracleTimeout`.
58 pub data_buffer: Pubkey,
59}
60
61impl Default for OracleQueueAccountData {
62 fn default() -> Self {
63 unsafe { std::mem::zeroed() }
64 }
65}
66
67impl OracleQueueAccountData {
68 pub fn size() -> usize {
69 std::mem::size_of::<OracleQueueAccountData>() + 8
70 }
71
72 pub fn convert_buffer(buf: &mut [u8]) -> &mut [Pubkey] {
73 try_cast_slice_mut(&mut buf[8..]).unwrap()
74 }
75
76 pub fn len(&self) -> u32 {
77 self.size
78 }
79
80 pub fn is_empty(&self) -> bool {
81 self.size == 0
82 }
83
84 pub fn get_mint(&self) -> Pubkey {
85 if self.mint == Pubkey::default() {
86 return *TOKEN_PID;
87 }
88 self.mint
89 }
90
91 pub fn max_round_rewards(&self, batch_size: u32) -> u64 {
92 self.reward
93 .checked_mul(batch_size.checked_add(1).unwrap().into())
94 .unwrap()
95 }
96
97 /// Returns the deserialized Switchboard OracleQueue account
98 ///
99 /// # Arguments
100 ///
101 /// * `account_info` - A Solana AccountInfo referencing an existing Switchboard OracleQueue
102 ///
103 /// # Examples
104 ///
105 /// ```ignore
106 /// use switchboard_solana::OracleQueueAccountData;
107 ///
108 /// let oracle_queue = OracleQueueAccountData::new(queue_account_info)?;
109 /// ```
110 pub fn new<'info>(
111 account_info: &'info AccountInfo<'info>,
112 ) -> anchor_lang::Result<Ref<'info, Self>> {
113 let data = account_info.try_borrow_data()?;
114 if data.len() < OracleQueueAccountData::discriminator().len() {
115 return Err(ErrorCode::AccountDiscriminatorNotFound.into());
116 }
117
118 let mut disc_bytes = [0u8; 8];
119 disc_bytes.copy_from_slice(&data[..8]);
120 if disc_bytes != OracleQueueAccountData::discriminator() {
121 return Err(ErrorCode::AccountDiscriminatorMismatch.into());
122 }
123
124 Ok(Ref::map(data, |data| {
125 bytemuck::from_bytes(&data[8..std::mem::size_of::<OracleQueueAccountData>() + 8])
126 }))
127 }
128
129 /// Returns the deserialized Switchboard OracleQueue account
130 ///
131 /// # Arguments
132 ///
133 /// * `data` - A Solana AccountInfo's data buffer
134 ///
135 /// # Examples
136 ///
137 /// ```ignore
138 /// use switchboard_solana::OracleQueueAccountData;
139 ///
140 /// let oracle_queue = OracleQueueAccountData::new(oracle_account_info.try_borrow_data()?)?;
141 /// ```
142 pub fn new_from_bytes(data: &[u8]) -> anchor_lang::Result<&OracleQueueAccountData> {
143 if data.len() < OracleQueueAccountData::discriminator().len() {
144 return Err(ErrorCode::AccountDiscriminatorNotFound.into());
145 }
146
147 let mut disc_bytes = [0u8; 8];
148 disc_bytes.copy_from_slice(&data[..8]);
149 if disc_bytes != OracleQueueAccountData::discriminator() {
150 return Err(ErrorCode::AccountDiscriminatorMismatch.into());
151 }
152
153 Ok(bytemuck::from_bytes(
154 &data[8..std::mem::size_of::<OracleQueueAccountData>() + 8],
155 ))
156 }
157}