use faster_hex::hex_string;
use rust_decimal::prelude::*;
use crate::prelude::*;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(packed)]
pub struct PackedQuoteHeader {
pub signed_slothash: [u8; 32],
}
impl borsh::BorshSerialize for PackedQuoteHeader {
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
let slothash = self.signed_slothash;
writer.write_all(&slothash)?;
Ok(())
}
}
impl borsh::BorshDeserialize for PackedQuoteHeader {
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
let mut signed_slothash = [0u8; 32];
reader.read_exact(&mut signed_slothash)?;
Ok(Self { signed_slothash })
}
}
#[cfg(feature = "anchor")]
impl anchor_lang::AnchorDeserialize for PackedQuoteHeader {
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
<Self as borsh::BorshDeserialize>::deserialize_reader(reader)
}
}
#[cfg(feature = "anchor")]
impl anchor_lang::AnchorSerialize for PackedQuoteHeader {
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
<Self as borsh::BorshSerialize>::serialize(self, writer)
}
}
#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for PackedQuoteHeader {}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(packed)]
pub struct PackedFeedInfo {
pub feed_id: [u8; 32],
pub feed_value: i128,
pub min_oracle_samples: u8,
}
impl borsh::BorshSerialize for PackedFeedInfo {
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
let feed_id = self.feed_id;
let feed_value = self.feed_value;
let min_oracle_samples = self.min_oracle_samples;
writer.write_all(&feed_id)?;
writer.write_all(&feed_value.to_le_bytes())?;
writer.write_all(&[min_oracle_samples])?;
Ok(())
}
}
impl borsh::BorshDeserialize for PackedFeedInfo {
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
let mut feed_id = [0u8; 32];
reader.read_exact(&mut feed_id)?;
let mut value_bytes = [0u8; 16];
reader.read_exact(&mut value_bytes)?;
let feed_value = i128::from_le_bytes(value_bytes);
let mut min_samples = [0u8; 1];
reader.read_exact(&mut min_samples)?;
let min_oracle_samples = min_samples[0];
Ok(Self {
feed_id,
feed_value,
min_oracle_samples,
})
}
}
#[cfg(feature = "anchor")]
impl anchor_lang::AnchorDeserialize for PackedFeedInfo {
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
<Self as borsh::BorshDeserialize>::deserialize_reader(reader)
}
}
#[cfg(feature = "anchor")]
impl anchor_lang::AnchorSerialize for PackedFeedInfo {
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
<Self as borsh::BorshSerialize>::serialize(self, writer)
}
}
#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for PackedFeedInfo {}
impl PackedFeedInfo {
pub const PACKED_SIZE: usize = 49;
#[inline(always)]
pub fn feed_id(&self) -> &[u8; 32] {
&self.feed_id
}
#[inline(always)]
pub fn hex_id(&self) -> String {
String::from("0x") + &hex_string(self.feed_id())
}
#[inline(always)]
pub fn feed_value(&self) -> i128 {
self.feed_value
}
#[inline(always)]
pub fn value(&self) -> Decimal {
Decimal::from_i128_with_scale(self.feed_value(), PRECISION).normalize()
}
#[inline(always)]
pub fn min_oracle_samples(&self) -> u8 {
self.min_oracle_samples
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_packed_feed_info_layout() {
let mut data = [0u8; 49];
data[0..32].fill(0x42);
let feed_value_scaled: i128 = 115525650000000000000000i128;
let value_bytes = feed_value_scaled.to_le_bytes();
data[32..48].copy_from_slice(&value_bytes);
data[48] = 5;
let feed_info = unsafe { &*(data.as_ptr() as *const PackedFeedInfo) };
let raw_value = feed_info.feed_value();
println!("Raw feed value: {}", raw_value);
println!("Expected: {}", feed_value_scaled);
assert_eq!(raw_value, feed_value_scaled);
let decimal_value = feed_info.value();
println!("Decimal value: {}", decimal_value);
assert_eq!(feed_info.min_oracle_samples(), 5);
assert_eq!(feed_info.feed_id()[0], 0x42);
println!(
"✅ Test passed! Feed value reads correctly: {}",
decimal_value
);
}
}