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