Ver código fonte

Merge pull request #2849 from pyth-network/pyth-stylus-final-functions

feat(stylus): implement queryPriceFeed, priceFeedExists functions, clean tests
Ayush Suresh 4 meses atrás
pai
commit
c5059518cc

+ 2 - 0
target_chains/stylus/contracts/pyth-receiver/src/error.rs

@@ -19,6 +19,7 @@ pub enum PythReceiverError {
     TooManyUpdates,
     PriceFeedNotFoundWithinRange,
     NoFreshUpdate,
+    PriceFeedNotFound,
 }
 
 impl core::fmt::Debug for PythReceiverError {
@@ -47,6 +48,7 @@ impl From<PythReceiverError> for Vec<u8> {
             PythReceiverError::TooManyUpdates => 15,
             PythReceiverError::PriceFeedNotFoundWithinRange => 16,
             PythReceiverError::NoFreshUpdate => 17,
+            PythReceiverError::PriceFeedNotFound => 18,
         }]
     }
 }

+ 120 - 56
target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs

@@ -9,11 +9,6 @@ mod test {
     use pythnet_sdk::wire::v1::{AccumulatorUpdateData, Proof};
     use std::time::Duration;
     use wormhole_contract::WormholeContract;
-    const TEST_PRICE_ID: [u8; 32] = [
-        0xe6, 0x2d, 0xf6, 0xc8, 0xb4, 0xa8, 0x5f, 0xe1, 0xa6, 0x7d, 0xb4, 0x4d, 0xc1, 0x2d, 0xe5,
-        0xdb, 0x33, 0x0f, 0x7a, 0xc6, 0x6b, 0x72, 0xdc, 0x65, 0x8a, 0xfe, 0xdf, 0x0f, 0x4a, 0x41,
-        0x5b, 0x43,
-    ];
 
     const PYTHNET_CHAIN_ID: u16 = 26;
     const PYTHNET_EMITTER_ADDRESS: [u8; 32] = [
@@ -102,7 +97,7 @@ mod test {
     ) {
         pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice);
 
-        let update_data = good_update1();
+        let update_data = ban_usd_update();
         let update_fee = mock_get_update_fee(update_data.clone()).unwrap();
 
         alice.fund(update_fee);
@@ -112,9 +107,11 @@ mod test {
             .update_price_feeds(update_data);
         assert!(result.is_ok());
 
-        let price_result = pyth_contract.sender(alice).get_price_unsafe(TEST_PRICE_ID);
+        let price_result = pyth_contract
+            .sender(alice)
+            .get_price_unsafe(ban_usd_feed_id());
         assert!(price_result.is_ok());
-        assert_eq!(price_result.unwrap(), good_update1_results());
+        assert_eq!(price_result.unwrap(), ban_usd_results_get_price());
     }
 
     #[motsu::test]
@@ -127,7 +124,7 @@ mod test {
 
         alice.fund(U256::from(200));
 
-        let update_data = good_update1();
+        let update_data = ban_usd_update();
         let update_fee = mock_get_update_fee(update_data.clone()).unwrap();
         let small_update_fee = update_fee / U256::from(2);
 
@@ -146,10 +143,10 @@ mod test {
     ) {
         pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice);
 
-        let update_data1 = good_update1();
+        let update_data1 = ban_usd_update();
         let update_fee1 = mock_get_update_fee(update_data1.clone()).unwrap();
 
-        let update_data2 = good_update2();
+        let update_data2 = btc_usd_update();
         let update_fee2 = mock_get_update_fee(update_data2.clone()).unwrap();
 
         alice.fund(update_fee1 + update_fee2);
@@ -164,9 +161,11 @@ mod test {
             .update_price_feeds(update_data2);
         assert!(result2.is_ok());
 
-        let price_result = pyth_contract.sender(alice).get_price_unsafe(TEST_PRICE_ID);
+        let price_result = pyth_contract
+            .sender(alice)
+            .get_price_unsafe(ban_usd_feed_id());
         assert!(price_result.is_ok());
-        assert_eq!(price_result.unwrap(), good_update2_results());
+        assert_eq!(price_result.unwrap(), ban_usd_results_get_price());
     }
 
     #[motsu::test]
@@ -177,7 +176,9 @@ mod test {
     ) {
         pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice);
 
-        let price_result = pyth_contract.sender(alice).get_price_unsafe(TEST_PRICE_ID);
+        let price_result = pyth_contract
+            .sender(alice)
+            .get_price_unsafe(ban_usd_feed_id());
         assert!(price_result.is_err());
         assert_eq!(
             price_result.unwrap_err(),
@@ -219,7 +220,7 @@ mod test {
         MockClock::set_time(Duration::from_secs(1761573860));
         pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice);
 
-        let update_data = good_update2();
+        let update_data = btc_usd_update();
         let update_fee = mock_get_update_fee(update_data.clone()).unwrap();
 
         alice.fund(update_fee);
@@ -231,9 +232,9 @@ mod test {
 
         let price_result = pyth_contract
             .sender(alice)
-            .get_price_no_older_than(TEST_PRICE_ID, u64::MAX);
+            .get_price_no_older_than(btc_usd_feed_id(), u64::MAX);
         assert!(price_result.is_ok());
-        assert_eq!(price_result.unwrap(), good_update2_results());
+        assert_eq!(price_result.unwrap(), btc_usd_results_get_price());
     }
 
     #[motsu::test]
@@ -245,7 +246,7 @@ mod test {
         MockClock::set_time(Duration::from_secs(1761573860));
         pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice);
 
-        let update_data = good_update2();
+        let update_data = btc_usd_update();
         let update_fee = mock_get_update_fee(update_data.clone()).unwrap();
 
         alice.fund(update_fee);
@@ -257,7 +258,8 @@ mod test {
 
         let price_result = pyth_contract
             .sender(alice)
-            .get_price_no_older_than(TEST_PRICE_ID, 1);
+            .get_price_no_older_than(btc_usd_feed_id(), 1);
+        println!("Price result: {:?}", price_result);
         assert!(price_result.is_err());
         assert_eq!(
             price_result.unwrap_err(),
@@ -266,14 +268,14 @@ mod test {
     }
 
     #[motsu::test]
-    fn test_multiple_updates_in_same_vaa_different_ids_updates_both(
+    fn test_multiple_updates_different_ids_updates_both(
         pyth_contract: Contract<PythReceiver>,
         wormhole_contract: Contract<WormholeContract>,
         alice: Address,
     ) {
         pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice);
 
-        let update_data = multiple_updates_same_vaa();
+        let update_data = multiple_updates_diff_vaa();
         let update_fee = mock_get_update_fee(update_data.clone()).unwrap();
 
         alice.fund(update_fee);
@@ -283,35 +285,38 @@ mod test {
             .update_price_feeds(update_data);
         assert!(result.is_ok());
 
-        let first_id: [u8; 32] = [
-            0xe6, 0x2d, 0xf6, 0xc8, 0xb4, 0xa8, 0x5f, 0xe1, 0xa6, 0x7d, 0xb4, 0x4d, 0xc1, 0x2d,
-            0xe5, 0xdb, 0x33, 0x0f, 0x7a, 0xc6, 0x6b, 0x72, 0xdc, 0x65, 0x8a, 0xfe, 0xdf, 0x0f,
-            0x4a, 0x41, 0x5b, 0x43,
-        ];
-        let second_id: [u8; 32] = [
-            0xff, 0x61, 0x49, 0x1a, 0x93, 0x11, 0x12, 0xdd, 0xf1, 0xbd, 0x81, 0x47, 0xcd, 0x1b,
-            0x64, 0x13, 0x75, 0xf7, 0x9f, 0x58, 0x25, 0x12, 0x6d, 0x66, 0x54, 0x80, 0x87, 0x46,
-            0x34, 0xfd, 0x0a, 0xce,
-        ];
-
-        let first_price_result = pyth_contract.sender(alice).get_price_unsafe(first_id);
+        let first_price_result = pyth_contract
+            .sender(alice)
+            .get_price_unsafe(ban_usd_feed_id());
         assert!(first_price_result.is_ok());
-        assert_eq!(first_price_result.unwrap(), multiple_updates_results()[0]);
+        assert_eq!(
+            first_price_result.unwrap(),
+            multiple_updates_diff_vaa_results_get_price()[0]
+        );
 
-        let second_price_result = pyth_contract.sender(alice).get_price_unsafe(second_id);
+        let second_price_result = pyth_contract
+            .sender(alice)
+            .get_price_unsafe(btc_usd_feed_id());
         assert!(second_price_result.is_ok());
-        assert_eq!(second_price_result.unwrap(), multiple_updates_results()[1]);
+        assert_eq!(
+            second_price_result.unwrap(),
+            multiple_updates_diff_vaa_results_get_price()[1]
+        );
     }
 
     #[motsu::test]
-    fn test_multiple_updates_different_ids_updates_both(
+    fn test_price_feed_exists(
         pyth_contract: Contract<PythReceiver>,
         wormhole_contract: Contract<WormholeContract>,
         alice: Address,
     ) {
         pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice);
 
-        let update_data = multiple_updates_diff_vaa();
+        assert!(!pyth_contract
+            .sender(alice)
+            .price_feed_exists(ban_usd_feed_id()));
+
+        let update_data = ban_usd_update();
         let update_fee = mock_get_update_fee(update_data.clone()).unwrap();
 
         alice.fund(update_fee);
@@ -321,35 +326,94 @@ mod test {
             .update_price_feeds(update_data);
         assert!(result.is_ok());
 
-        let first_id: [u8; 32] = [
-            0x3f, 0xa4, 0x25, 0x28, 0x48, 0xf9, 0xf0, 0xa1, 0x48, 0x0b, 0xe6, 0x27, 0x45, 0xa4,
-            0x62, 0x9d, 0x9e, 0xb1, 0x32, 0x2a, 0xeb, 0xab, 0x8a, 0x79, 0x1e, 0x34, 0x4b, 0x3b,
-            0x9c, 0x1a, 0xdc, 0xf5,
-        ];
-        let second_id: [u8; 32] = TEST_PRICE_ID;
+        assert!(pyth_contract
+            .sender(alice)
+            .price_feed_exists(ban_usd_feed_id()));
+    }
 
-        let first_price_result = pyth_contract.sender(alice).get_price_unsafe(first_id);
-        assert!(first_price_result.is_ok());
-        assert_eq!(
-            first_price_result.unwrap(),
-            multiple_updates_diff_vaa_results()[0]
-        );
+    #[motsu::test]
+    fn test_query_price_feed_doesnt_exist(
+        pyth_contract: Contract<PythReceiver>,
+        wormhole_contract: Contract<WormholeContract>,
+        alice: Address,
+    ) {
+        pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice);
 
-        let second_price_result = pyth_contract.sender(alice).get_price_unsafe(second_id);
-        assert!(second_price_result.is_ok());
+        let price_result = pyth_contract
+            .sender(alice)
+            .query_price_feed(ban_usd_feed_id());
+
+        assert!(price_result.is_err());
         assert_eq!(
-            second_price_result.unwrap(),
-            multiple_updates_diff_vaa_results()[1]
+            price_result.unwrap_err(),
+            PythReceiverError::PriceFeedNotFound
         );
     }
 
     #[motsu::test]
-    fn test_multiple_updates_same_id_updates_latest(
+    fn test_query_price_feed_after_one_feed_update(
         pyth_contract: Contract<PythReceiver>,
         wormhole_contract: Contract<WormholeContract>,
         alice: Address,
     ) {
         pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice);
-        alice.fund(U256::from(200));
+
+        let update_data = ban_usd_update();
+        let update_fee = mock_get_update_fee(update_data.clone()).unwrap();
+
+        alice.fund(update_fee);
+
+        let result = pyth_contract
+            .sender_and_value(alice, update_fee)
+            .update_price_feeds(update_data);
+
+        assert!(result.is_ok());
+
+        let price_result = pyth_contract
+            .sender(alice)
+            .query_price_feed(ban_usd_feed_id());
+
+        assert!(price_result.is_ok());
+        assert_eq!(price_result.unwrap(), ban_usd_results_full());
+    }
+
+    #[motsu::test]
+    fn test_query_price_feed_after_multiple_updates(
+        pyth_contract: Contract<PythReceiver>,
+        wormhole_contract: Contract<WormholeContract>,
+        alice: Address,
+    ) {
+        pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice);
+
+        let update_data = multiple_updates_diff_vaa();
+        let update_fee = mock_get_update_fee(update_data.clone()).unwrap();
+
+        alice.fund(update_fee);
+
+        let result = pyth_contract
+            .sender_and_value(alice, update_fee)
+            .update_price_feeds(update_data);
+
+        assert!(result.is_ok());
+
+        let price_result1 = pyth_contract
+            .sender(alice)
+            .query_price_feed(ban_usd_feed_id());
+
+        assert!(price_result1.is_ok());
+        assert_eq!(
+            price_result1.unwrap(),
+            multiple_updates_diff_vaa_results_full()[0]
+        );
+
+        let price_result2 = pyth_contract
+            .sender(alice)
+            .query_price_feed(btc_usd_feed_id());
+
+        assert!(price_result2.is_ok());
+        assert_eq!(
+            price_result2.unwrap(),
+            multiple_updates_diff_vaa_results_full()[1]
+        );
     }
 }

+ 84 - 53
target_chains/stylus/contracts/pyth-receiver/src/lib.rs

@@ -15,7 +15,7 @@ mod test_data;
 #[cfg(test)]
 use mock_instant::global::MockClock;
 
-use alloc::{collections::BTreeMap, vec::Vec};
+use alloc::vec::Vec;
 use stylus_sdk::{
     alloy_primitives::{Address, FixedBytes, I32, I64, U16, U256, U32, U64},
     call::Call,
@@ -39,7 +39,7 @@ use pythnet_sdk::{
         },
     },
 };
-use structs::{DataSource, DataSourceStorage, PriceInfoReturn, PriceInfoStorage};
+use structs::{DataSource, DataSourceStorage, PriceFeedReturn, PriceFeedStorage, PriceReturn};
 use wormhole_vaas::{Readable, Vaa, Writeable};
 
 sol_interface! {
@@ -63,7 +63,7 @@ pub struct PythReceiver {
     pub governance_data_source_emitter_address: StorageFixedBytes<32>,
     pub last_executed_governance_sequence: StorageUint<64, 1>,
     pub governance_data_source_index: StorageUint<32, 1>,
-    pub latest_price_info: StorageMap<FixedBytes<32>, PriceInfoStorage>,
+    pub latest_price_info: StorageMap<FixedBytes<32>, PriceFeedStorage>,
     pub transaction_fee_in_wei: StorageU256,
 }
 
@@ -110,16 +110,23 @@ impl PythReceiver {
         }
     }
 
-    pub fn get_price_unsafe(&self, id: [u8; 32]) -> Result<PriceInfoReturn, PythReceiverError> {
+    pub fn price_feed_exists(&self, id: [u8; 32]) -> bool {
+        let id_fb = FixedBytes::<32>::from(id);
+        let price_info = self.latest_price_info.get(id_fb);
+        return price_info.publish_time.get() != U64::ZERO;
+    }
+
+    pub fn query_price_feed(&self, id: [u8; 32]) -> Result<PriceFeedReturn, 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);
+            return Err(PythReceiverError::PriceFeedNotFound);
         }
 
         Ok((
+            id_fb,
             price_info.publish_time.get(),
             price_info.expo.get(),
             price_info.price.get(),
@@ -129,19 +136,36 @@ impl PythReceiver {
         ))
     }
 
+    pub fn get_price_unsafe(&self, id: [u8; 32]) -> Result<PriceReturn, 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.price.get(),
+            price_info.conf.get(),
+            price_info.expo.get(),
+            price_info.publish_time.get(),
+        ))
+    }
+
     pub fn get_price_no_older_than(
         &self,
         id: [u8; 32],
         age: u64,
-    ) -> Result<PriceInfoReturn, PythReceiverError> {
+    ) -> Result<PriceReturn, PythReceiverError> {
         let price_info = self.get_price_unsafe(id)?;
-        if !self.is_no_older_than(price_info.0, age) {
+        if !self.is_no_older_than(price_info.3, age) {
             return Err(PythReceiverError::NewPriceUnavailable);
         }
         Ok(price_info)
     }
 
-    pub fn get_ema_price_unsafe(&self, id: [u8; 32]) -> Result<PriceInfoReturn, PythReceiverError> {
+    pub fn get_ema_price_unsafe(&self, id: [u8; 32]) -> Result<PriceReturn, PythReceiverError> {
         let id_fb = FixedBytes::<32>::from(id);
         let price_info = self.latest_price_info.get(id_fb);
 
@@ -150,12 +174,10 @@ impl PythReceiver {
         }
 
         Ok((
-            price_info.publish_time.get(),
-            price_info.expo.get(),
-            price_info.ema_price.get(),
-            price_info.ema_conf.get(),
             price_info.ema_price.get(),
             price_info.ema_conf.get(),
+            price_info.expo.get(),
+            price_info.publish_time.get(),
         ))
     }
 
@@ -163,9 +185,9 @@ impl PythReceiver {
         &self,
         id: [u8; 32],
         age: u64,
-    ) -> Result<PriceInfoReturn, PythReceiverError> {
+    ) -> Result<PriceReturn, PythReceiverError> {
         let price_info = self.get_ema_price_unsafe(id)?;
-        if !self.is_no_older_than(price_info.0, age) {
+        if !self.is_no_older_than(price_info.3, age) {
             return Err(PythReceiverError::NewPriceUnavailable);
         }
         Ok(price_info)
@@ -224,7 +246,7 @@ impl PythReceiver {
         min_publish_time: u64,
         max_publish_time: u64,
         unique: bool,
-    ) -> Result<Vec<([u8; 32], PriceInfoReturn)>, PythReceiverError> {
+    ) -> Result<Vec<PriceFeedReturn>, PythReceiverError> {
         let price_pairs = self.parse_price_feed_updates_internal(
             update_data,
             min_publish_time,
@@ -232,19 +254,22 @@ impl PythReceiver {
             unique,
         )?;
 
-        for (price_id, price_return) in price_pairs.clone() {
-            let price_id_fb: FixedBytes<32> = FixedBytes::from(price_id);
+        for price_return in &price_pairs {
+            let price_id_fb: FixedBytes<32> = FixedBytes::from(price_return.0);
             let mut recent_price_info = self.latest_price_info.setter(price_id_fb);
 
-            if recent_price_info.publish_time.get() < price_return.0
+            if recent_price_info.publish_time.get() < price_return.1
                 || recent_price_info.price.get() == I64::ZERO
             {
-                recent_price_info.publish_time.set(price_return.0);
-                recent_price_info.expo.set(price_return.1);
-                recent_price_info.price.set(price_return.2);
-                recent_price_info.conf.set(price_return.3);
-                recent_price_info.ema_price.set(price_return.4);
-                recent_price_info.ema_conf.set(price_return.5);
+                recent_price_info
+                    .price_id
+                    .set(FixedBytes::from(price_return.0));
+                recent_price_info.publish_time.set(price_return.1);
+                recent_price_info.expo.set(price_return.2);
+                recent_price_info.price.set(price_return.3);
+                recent_price_info.conf.set(price_return.4);
+                recent_price_info.ema_price.set(price_return.5);
+                recent_price_info.ema_conf.set(price_return.6);
             }
         }
 
@@ -265,8 +290,10 @@ impl PythReceiver {
                 }
             }
         }
-        Ok(U256::from(total_num_updates).saturating_mul(self.single_update_fee_in_wei.get())
-            + self.transaction_fee_in_wei.get())
+        Ok(
+            U256::from(total_num_updates).saturating_mul(self.single_update_fee_in_wei.get())
+                + self.transaction_fee_in_wei.get(),
+        )
     }
 
     pub fn get_twap_update_fee(&self, _update_data: Vec<Vec<u8>>) -> U256 {
@@ -279,7 +306,7 @@ impl PythReceiver {
         price_ids: Vec<[u8; 32]>,
         min_publish_time: u64,
         max_publish_time: u64,
-    ) -> Result<Vec<PriceInfoReturn>, PythReceiverError> {
+    ) -> Result<Vec<PriceFeedReturn>, PythReceiverError> {
         let price_feeds = self.parse_price_feed_updates_with_config(
             vec![update_data],
             price_ids,
@@ -301,18 +328,18 @@ impl PythReceiver {
         check_uniqueness: bool,
         check_update_data_is_minimal: bool,
         store_updates_if_fresh: bool,
-    ) -> Result<Vec<PriceInfoReturn>, PythReceiverError> {
-        let mut all_parsed_price_pairs = Vec::new();
+    ) -> Result<Vec<PriceFeedReturn>, PythReceiverError> {
+        let mut all_parsed_price_feeds = Vec::new();
         for data in &update_data {
             if store_updates_if_fresh {
-                all_parsed_price_pairs.extend(self.update_price_feeds_internal(
+                all_parsed_price_feeds.extend(self.update_price_feeds_internal(
                     data.clone(),
                     min_allowed_publish_time,
                     max_allowed_publish_time,
                     check_uniqueness,
                 )?);
             } else {
-                all_parsed_price_pairs.extend(self.parse_price_feed_updates_internal(
+                all_parsed_price_feeds.extend(self.parse_price_feed_updates_internal(
                     data.clone(),
                     min_allowed_publish_time,
                     max_allowed_publish_time,
@@ -321,22 +348,18 @@ impl PythReceiver {
             }
         }
 
-        if check_update_data_is_minimal && all_parsed_price_pairs.len() != price_ids.len() {
+        if check_update_data_is_minimal && all_parsed_price_feeds.len() != price_ids.len() {
             return Err(PythReceiverError::InvalidUpdateData);
         }
 
-        let mut result: Vec<PriceInfoReturn> = Vec::with_capacity(price_ids.len());
-        let mut price_map: BTreeMap<[u8; 32], PriceInfoReturn> = BTreeMap::new();
-
-        for (price_id, price_info) in all_parsed_price_pairs {
-            if !price_map.contains_key(&price_id) {
-                price_map.insert(price_id, price_info);
-            }
-        }
+        let mut result: Vec<PriceFeedReturn> = Vec::with_capacity(price_ids.len());
 
         for price_id in price_ids {
-            if let Some(price_info) = price_map.get(&price_id) {
-                result.push(*price_info);
+            if let Some(price_info) = all_parsed_price_feeds
+                .iter()
+                .find(|feed| feed.0 == price_id)
+            {
+                result.push(price_info.clone());
             } else {
                 return Err(PythReceiverError::PriceFeedNotFoundWithinRange);
             }
@@ -351,7 +374,7 @@ impl PythReceiver {
         min_allowed_publish_time: u64,
         max_allowed_publish_time: u64,
         check_uniqueness: bool,
-    ) -> Result<Vec<([u8; 32], PriceInfoReturn)>, PythReceiverError> {
+    ) -> Result<Vec<PriceFeedReturn>, PythReceiverError> {
         let update_data_array: &[u8] = &update_data;
         // Check the first 4 bytes of the update_data_array for the magic header
         if update_data_array.len() < 4 {
@@ -368,7 +391,7 @@ impl PythReceiver {
         let accumulator_update = AccumulatorUpdateData::try_from_slice(&update_data_array)
             .map_err(|_| PythReceiverError::InvalidAccumulatorMessage)?;
 
-        let mut price_feeds: BTreeMap<[u8; 32], PriceInfoReturn> = BTreeMap::new();
+        let mut price_feeds = Vec::new();
 
         match accumulator_update.proof {
             Proof::WormholeMerkle { vaa, updates } => {
@@ -422,9 +445,9 @@ impl PythReceiver {
                                 return Err(PythReceiverError::PriceFeedNotFoundWithinRange);
                             }
 
+                            let price_id_fb = FixedBytes::<32>::from(price_feed_message.feed_id);
+
                             if check_uniqueness {
-                                let price_id_fb =
-                                    FixedBytes::<32>::from(price_feed_message.feed_id);
                                 let prev_price_info = self.latest_price_info.get(price_id_fb);
                                 let prev_publish_time =
                                     prev_price_info.publish_time.get().to::<u64>();
@@ -436,16 +459,24 @@ impl PythReceiver {
                                 }
                             }
 
+                            let expo = I32::try_from(price_feed_message.exponent)
+                                .map_err(|_| PythReceiverError::InvalidUpdateData)?;
+                            let price = I64::try_from(price_feed_message.price)
+                                .map_err(|_| PythReceiverError::InvalidUpdateData)?;
+                            let ema_price = I64::try_from(price_feed_message.ema_price)
+                                .map_err(|_| PythReceiverError::InvalidUpdateData)?;
+
                             let price_info_return = (
+                                price_id_fb,
                                 U64::from(publish_time),
-                                I32::from_be_bytes(price_feed_message.exponent.to_be_bytes()),
-                                I64::from_be_bytes(price_feed_message.price.to_be_bytes()),
+                                expo,
+                                price,
                                 U64::from(price_feed_message.conf),
-                                I64::from_be_bytes(price_feed_message.ema_price.to_be_bytes()),
+                                ema_price,
                                 U64::from(price_feed_message.ema_conf),
                             );
 
-                            price_feeds.insert(price_feed_message.feed_id, price_info_return);
+                            price_feeds.push(price_info_return);
                         }
                         _ => {
                             return Err(PythReceiverError::InvalidAccumulatorMessageType);
@@ -455,14 +486,14 @@ impl PythReceiver {
             }
         };
 
-        Ok(price_feeds.into_iter().collect())
+        Ok(price_feeds)
     }
 
     pub fn parse_twap_price_feed_updates(
         &mut self,
         _update_data: Vec<Vec<u8>>,
         _price_ids: Vec<[u8; 32]>,
-    ) -> Vec<PriceInfoReturn> {
+    ) -> Vec<PriceFeedReturn> {
         Vec::new()
     }
 
@@ -472,7 +503,7 @@ impl PythReceiver {
         price_ids: Vec<[u8; 32]>,
         min_publish_time: u64,
         max_publish_time: u64,
-    ) -> Result<Vec<PriceInfoReturn>, PythReceiverError> {
+    ) -> Result<Vec<PriceFeedReturn>, PythReceiverError> {
         let price_feeds = self.parse_price_feed_updates_with_config(
             update_data,
             price_ids,

+ 8 - 4
target_chains/stylus/contracts/pyth-receiver/src/structs.rs

@@ -36,7 +36,8 @@ impl StorageKey for DataSource {
     }
 }
 #[storage]
-pub struct PriceInfoStorage {
+pub struct PriceFeedStorage {
+    pub price_id: StorageFixedBytes<32>,
     pub publish_time: StorageU64,
     pub expo: StorageI32,
     pub price: StorageI64,
@@ -46,9 +47,9 @@ pub struct PriceInfoStorage {
 }
 
 // Addressing nit -- running into some versioning issues that preclude me
-// from returning the PriceInfo struct directly. Need to figure that out.
+// from returning the PriceFeed struct directly. Need to figure that out.
 
-// pub struct PriceInfo {
+// pub struct PriceFeed {
 //     pub publish_time: U64,
 //     pub expo: I32,
 //     pub price: I64,
@@ -57,7 +58,10 @@ pub struct PriceInfoStorage {
 //     pub ema_conf: U64,
 // }
 
-pub type PriceInfoReturn = (U64, I32, I64, U64, I64, U64);
+pub type PriceFeedReturn = (FixedBytes<32>, U64, I32, I64, U64, I64, U64);
+
+// (price, conf, expo, publish_time)
+pub type PriceReturn = (I64, U64, I32, U64);
 
 #[cfg(test)]
 mod tests {

Diferenças do arquivo suprimidas por serem muito extensas
+ 2 - 2
target_chains/stylus/contracts/pyth-receiver/src/test_data.rs


Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff