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}