use super::super::oracle_job::OracleJob;
use super::super::lut_owner::LutOwner;
use super::super::crossbar::CrossbarClient;
use anyhow::{Context, Error as AnyhowError};
use bytemuck;
use rust_decimal::Decimal;
use anchor_lang::prelude::Pubkey;
pub const PRECISION: u32 = 18;
pub const MAX_SAMPLES: usize = 32;
#[repr(C)]
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
pub struct CurrentResult {
pub value: i128,
pub std_dev: i128,
pub mean: i128,
pub range: i128,
pub min_value: i128,
pub max_value: i128,
pub num_samples: u8,
pub padding1: [u8; 7],
pub slot: u64,
pub min_slot: u64,
pub max_slot: u64,
}
impl CurrentResult {
pub fn value(&self) -> Decimal {
Decimal::from_i128_with_scale(self.value, PRECISION)
}
pub fn std_dev(&self) -> Decimal {
Decimal::from_i128_with_scale(self.std_dev, PRECISION)
}
pub fn mean(&self) -> Decimal {
Decimal::from_i128_with_scale(self.mean, PRECISION)
}
pub fn range(&self) -> Decimal {
Decimal::from_i128_with_scale(self.range, PRECISION)
}
pub fn min_value(&self) -> Decimal {
Decimal::from_i128_with_scale(self.min_value, PRECISION)
}
pub fn max_value(&self) -> Decimal {
Decimal::from_i128_with_scale(self.max_value, PRECISION)
}
pub fn result_slot(&self) -> u64 {
self.slot
}
pub fn min_slot(&self) -> u64 {
self.min_slot
}
pub fn max_slot(&self) -> u64 {
self.max_slot
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
pub struct OracleSubmission {
pub oracle: Pubkey,
pub slot: u64,
pub landed_at: u64,
pub value: i128,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
pub struct PullFeedAccountData {
pub submissions: [OracleSubmission; 32],
pub authority: Pubkey,
pub queue: Pubkey,
pub feed_hash: [u8; 32],
pub initialized_at: i64,
pub permissions: u64,
pub max_variance: u64,
pub min_responses: u32,
pub name: [u8; 32],
_padding1: [u8; 3],
pub min_sample_size: u8,
pub last_update_timestamp: i64,
pub lut_slot: u64,
pub ipfs_hash: [u8; 32], pub result: CurrentResult,
pub max_staleness: u32,
_ebuf4: [u8; 20],
_ebuf3: [u8; 24],
_ebuf2: [u8; 256],
_ebuf1: [u8; 512],
}
impl OracleSubmission {
pub fn is_empty(&self) -> bool {
self.slot == 0
}
pub fn value(&self) -> Decimal {
Decimal::from_i128_with_scale(self.value, PRECISION)
}
}
impl PullFeedAccountData {
pub fn value(&self) -> Decimal {
self.result.value()
}
pub fn range(&self) -> Decimal {
self.result.range()
}
pub fn min_value(&self) -> Decimal {
self.result.min_value()
}
pub fn max_value(&self) -> Decimal {
self.result.max_value()
}
pub fn result_slot(&self) -> u64 {
self.result.slot
}
pub fn feed_hash(&self) -> String {
hex::encode(self.feed_hash)
}
pub async fn fetch_jobs(
&self,
crossbar: &CrossbarClient,
) -> Result<Vec<OracleJob>, AnyhowError> {
let jobs_data = crossbar
.fetch(&self.feed_hash())
.await
.context("PullFeed.fetchUpdateIx: Failed to fetch jobs")?;
let jobs: Vec<OracleJob> = serde_json::from_value(jobs_data.get("jobs").unwrap().clone())
.context("PullFeed.fetchUpdateIx: Failed to deserialize jobs")?;
Ok(jobs)
}
}
impl LutOwner for PullFeedAccountData {
fn lut_slot(&self) -> u64 {
self.lut_slot
}
}