Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions target_chains/stylus/contracts/pyth-receiver/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use alloc::vec::Vec;

pub enum PythReceiverError {
PriceUnavailable
}

impl core::fmt::Debug for PythReceiverError {
fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
Ok(())
}
}

impl From<PythReceiverError> for Vec<u8> {
fn from(error: PythReceiverError) -> Vec<u8> {
vec![match error {
PythReceiverError::PriceUnavailable => 1,
}]
}
}
36 changes: 32 additions & 4 deletions target_chains/stylus/contracts/pyth-receiver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
extern crate alloc;

mod structs;
mod error;

use alloc::vec::Vec;
use stylus_sdk::{alloy_primitives::{U256, U64, I32, I64, FixedBytes},
prelude::*,
storage::{StorageAddress, StorageVec, StorageMap, StorageUint, StorageBool, StorageU256}};

use structs::{DataSourceStorage, PriceInfoReturn, PriceInfoStorage};
use error::{PythReceiverError};

#[storage]
#[entrypoint]
Expand All @@ -31,12 +33,31 @@ pub struct PythReceiver {

#[public]
impl PythReceiver {
pub fn get_price_unsafe(&self, _id: [u8; 32]) -> PriceInfoReturn {
(U64::ZERO, I32::ZERO, I64::ZERO, U64::ZERO, I64::ZERO, U64::ZERO)
pub fn get_price_unsafe(&self, _id: [u8; 32]) -> Result<PriceInfoReturn, PythReceiverError> {
let id_fb = FixedBytes::<32>::from(_id);

let price_info = self.latest_price_info.get(id_fb);

if price_info.publish_time.get() == U64::ZERO {
return Err(PythReceiverError::PriceUnavailable);
}

Ok((
price_info.publish_time.get(),
price_info.expo.get(),
price_info.price.get(),
price_info.conf.get(),
price_info.ema_price.get(),
price_info.ema_conf.get(),
))
}

pub fn get_price_no_older_than(&self, _id: [u8; 32], _age: u64) -> PriceInfoReturn {
(U64::ZERO, I32::ZERO, I64::ZERO, U64::ZERO, I64::ZERO, U64::ZERO)
pub fn get_price_no_older_than(&self, _id: [u8; 32], _age: u64) -> Result<PriceInfoReturn, PythReceiverError> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessary right now (you can do this in a future PR,) but let's move the public components that users will consume like structs and errors into an SDK. That way they can import just the public SDK to consume prices and use the contracts. The private impls will stay in the contract, but will implement the public SDK interfaces. Example here.

let price_info = self.get_price_unsafe(_id)?;
if !self.is_no_older_than(price_info.0, _age) {
return Err(PythReceiverError::PriceUnavailable);
}
Ok(price_info)
}

pub fn get_ema_price_unsafe(&self, _id: [u8; 32]) -> PriceInfoReturn {
Expand Down Expand Up @@ -108,4 +129,11 @@ impl PythReceiver {
) -> Vec<PriceInfoReturn> {
Vec::new()
}

fn is_no_older_than(&self, publish_time: U64, max_age: u64) -> bool {
let current_u64: u64 = self.vm().block_timestamp();
let publish_time_u64: u64 = publish_time.to::<u64>();

current_u64.saturating_sub(publish_time_u64) <= max_age
}
}