switchboard_solana/oracle_program/accounts/
oracle.rs

1use crate::prelude::*;
2use std::cell::Ref;
3
4#[derive(Copy, Clone, AnchorSerialize, AnchorDeserialize)]
5pub enum OracleResponseType {
6    TypeSuccess,
7    TypeError,
8    TypeDisagreement,
9    TypeNoResponse,
10}
11
12#[zero_copy(unsafe)]
13#[derive(Default)]
14#[repr(packed)]
15pub struct OracleMetrics {
16    /// Number of consecutive successful update request.
17    pub consecutive_success: u64,
18    /// Number of consecutive update request that resulted in an error.
19    pub consecutive_error: u64,
20    /// Number of consecutive update request that resulted in a disagreement with the accepted median result.
21    pub consecutive_disagreement: u64,
22    /// Number of consecutive update request that were posted on-chain late and not included in an accepted result.
23    pub consecutive_late_response: u64,
24    /// Number of consecutive update request that resulted in a failure.
25    pub consecutive_failure: u64,
26    /// Total number of successful update request.
27    pub total_success: u128,
28    /// Total number of update request that resulted in an error.
29    pub total_error: u128,
30    /// Total number of update request that resulted in a disagreement with the accepted median result.
31    pub total_disagreement: u128,
32    /// Total number of update request that were posted on-chain late and not included in an accepted result.
33    pub total_late_response: u128,
34}
35
36#[account(zero_copy(unsafe))]
37#[repr(packed)]
38pub struct OracleAccountData {
39    /// Name of the oracle to store on-chain.
40    pub name: [u8; 32],
41    /// Metadata of the oracle to store on-chain.
42    pub metadata: [u8; 128],
43    /// The account delegated as the authority for making account changes or withdrawing funds from a staking wallet.
44    pub oracle_authority: Pubkey,
45    /// Unix timestamp when the oracle last heartbeated
46    pub last_heartbeat: i64,
47    /// Flag dictating if an oracle is active and has heartbeated before the queue's oracle timeout parameter.
48    pub num_in_use: u32,
49    // Must be unique per oracle account and authority should be a pda
50    /// Stake account and reward/slashing wallet.
51    pub token_account: Pubkey,
52    /// Public key of the oracle queue who has granted it permission to use its resources.
53    pub queue_pubkey: Pubkey,
54    /// Oracle track record.
55    pub metrics: OracleMetrics,
56    /// The PDA bump to derive the pubkey.
57    pub bump: u8,
58    /// Reserved for future info.
59    pub _ebuf: [u8; 255],
60}
61
62impl OracleAccountData {
63    pub fn size() -> usize {
64        8 + std::mem::size_of::<OracleAccountData>()
65    }
66
67    /// Returns the deserialized Switchboard Oracle account
68    ///
69    /// # Arguments
70    ///
71    /// * `account_info` - A Solana AccountInfo referencing an existing Switchboard Oracle
72    ///
73    /// # Examples
74    ///
75    /// ```ignore
76    /// use switchboard_solana::OracleAccountData;
77    ///
78    /// let oracle = OracleAccountData::new(oracle_account_info)?;
79    /// ```
80    pub fn new<'info>(
81        account_info: &'info AccountInfo<'info>,
82    ) -> anchor_lang::Result<Ref<'info, Self>> {
83        let data = account_info.try_borrow_data()?;
84        if data.len() < OracleAccountData::discriminator().len() {
85            return Err(ErrorCode::AccountDiscriminatorNotFound.into());
86        }
87
88        let mut disc_bytes = [0u8; 8];
89        disc_bytes.copy_from_slice(&data[..8]);
90        if disc_bytes != OracleAccountData::discriminator() {
91            return Err(ErrorCode::AccountDiscriminatorMismatch.into());
92        }
93
94        Ok(Ref::map(data, |data| {
95            bytemuck::from_bytes(&data[8..std::mem::size_of::<OracleAccountData>() + 8])
96        }))
97    }
98
99    /// Returns the deserialized Switchboard Oracle account
100    ///
101    /// # Arguments
102    ///
103    /// * `data` - A Solana AccountInfo's data buffer
104    ///
105    /// # Examples
106    ///
107    /// ```ignore
108    /// use switchboard_solana::OracleAccountData;
109    ///
110    /// let oracle = OracleAccountData::new(oracle_account_info.try_borrow_data()?)?;
111    /// ```
112    pub fn new_from_bytes(data: &[u8]) -> anchor_lang::Result<&OracleAccountData> {
113        if data.len() < OracleAccountData::discriminator().len() {
114            return Err(ErrorCode::AccountDiscriminatorNotFound.into());
115        }
116
117        let mut disc_bytes = [0u8; 8];
118        disc_bytes.copy_from_slice(&data[..8]);
119        if disc_bytes != OracleAccountData::discriminator() {
120            return Err(ErrorCode::AccountDiscriminatorMismatch.into());
121        }
122
123        Ok(bytemuck::from_bytes(
124            &data[8..std::mem::size_of::<OracleAccountData>() + 8],
125        ))
126    }
127}