From ac3d5055bee1e50c37a3fc998d2551e097dc70a7 Mon Sep 17 00:00:00 2001 From: Ayush Suresh Date: Wed, 9 Jul 2025 11:58:57 -0500 Subject: [PATCH 01/22] removing extraneous comments --- .../contracts/pyth-receiver/src/structs.rs | 44 ------------------- 1 file changed, 44 deletions(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs b/target_chains/stylus/contracts/pyth-receiver/src/structs.rs index 722eb7312a..9e95dc012a 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/structs.rs @@ -46,18 +46,6 @@ pub struct DataSource { pub emitter_address: FixedBytes<32>, } -// impl StorageKey for DataSourceStorage { -// fn to_slot(&self, root: B256) -> U256 { -// let chain_id: u16 = self.chain_id.get().to::(); -// let emitter_address = self.emitter_address.get(); - -// let bytes = serialize_data_source_to_bytes(chain_id, emitter_address.as_slice().try_into().unwrap()) -// .expect("Failed to serialize DataSource"); - -// keccak256(bytes).to_slot(root) -// } -// } - impl StorageKey for DataSource { fn to_slot(&self, root: B256) -> U256 { let chain_id: u16 = self.chain_id.to::(); @@ -69,24 +57,6 @@ impl StorageKey for DataSource { keccak256(bytes).to_slot(root) } } - -// pub trait GetDataSource { -// fn data_source(&self) -> DataSourceStorage; -// } - -// impl GetDataSource for VerifiedVM { -// fn data_source(&self) -> DataSourceStorage { -// let mut ds = DataSourceStorage { -// chain_id: StorageU16::new(storage_key!("chain_id")), -// emitter_address: StorageFixedBytes::<32>::new(storage_key!("emitter_address")), -// }; -// ds.chain_id.set(self.emitter_chain_id.into()); -// ds.emitter_address.set(self.emitter_address); -// ds -// } -// } - -// PriceInfo struct storing price information #[storage] pub struct PriceInfoStorage { pub publish_time: StorageU64, @@ -109,20 +79,6 @@ pub struct PriceInfoStorage { // pub ema_conf: U64, // } -// impl From<&PriceFeedMessage> for PriceInfo { -// fn from(price_feed_message: &PriceFeedMessage) -> Self { -// Self { -// publish_time: U64::from(price_feed_message.publish_time), -// expo: I32::from_be_bytes(price_feed_message.exponent.to_be_bytes()), -// price: I64::from_be_bytes(price_feed_message.price.to_be_bytes()), -// conf: U64::from(price_feed_message.conf), -// ema_price: I64::from_be_bytes(price_feed_message.ema_price.to_be_bytes()), -// ema_conf: U64::from(price_feed_message.ema_conf), -// } -// } -// } - -// PriceInfo struct storing price information pub type PriceInfoReturn = (U64, I32, I64, U64, I64, U64); #[cfg(test)] From 0f9de33304beb71bc9bc2f5578cc774b78a9945a Mon Sep 17 00:00:00 2001 From: Ayush Suresh Date: Wed, 9 Jul 2025 12:04:34 -0500 Subject: [PATCH 02/22] cleaned serialization --- .../contracts/pyth-receiver/src/structs.rs | 34 +++++-------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs b/target_chains/stylus/contracts/pyth-receiver/src/structs.rs index 9e95dc012a..abfcfd7d77 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/structs.rs @@ -1,5 +1,4 @@ -use alloc::{boxed::Box, format, vec::Vec}; -use pythnet_sdk::wire::to_vec; +use alloc::{vec::Vec}; use serde::Serialize; use stylus_sdk::alloy_primitives::{keccak256, FixedBytes, B256, I32, I64, U16, U256, U64}; use stylus_sdk::{ @@ -7,32 +6,17 @@ use stylus_sdk::{ storage::{StorageFixedBytes, StorageI32, StorageI64, StorageKey, StorageU16, StorageU64}, }; -#[derive(Serialize)] -struct SerializableDataSource { - chain_id: u16, - #[serde(with = "pythnet_sdk::wire::array")] - emitter_address: [u8; 32], -} - fn serialize_data_source_to_bytes( chain_id: u16, emitter_address: &[u8; 32], -) -> Result<[u8; 34], Box> { - let data_source = SerializableDataSource { - chain_id, - emitter_address: *emitter_address, - }; - - let bytes = to_vec::<_, byteorder::BE>(&data_source)?; - if bytes.len() != 34 { - return Err(format!("Expected 34 bytes, got {}", bytes.len()).into()); - } - +) -> [u8; 34] { let mut result = [0u8; 34]; - result.copy_from_slice(&bytes); - Ok(result) + result[0..2].copy_from_slice(&chain_id.to_be_bytes()); + result[2..].copy_from_slice(emitter_address); + result } + #[derive(Debug)] #[storage] pub struct DataSourceStorage { @@ -51,8 +35,7 @@ impl StorageKey for DataSource { let chain_id: u16 = self.chain_id.to::(); let emitter_address: [u8; 32] = self.emitter_address.as_slice().try_into().unwrap(); - let bytes = serialize_data_source_to_bytes(chain_id, &emitter_address) - .expect("Failed to serialize DataSource"); + let bytes = serialize_data_source_to_bytes(chain_id, &emitter_address); keccak256(bytes).to_slot(root) } @@ -100,8 +83,7 @@ mod tests { expected_bytes[0..2].copy_from_slice(&chain_id.to_be_bytes()); expected_bytes[2..].copy_from_slice(&emitter_address); - let actual_bytes = serialize_data_source_to_bytes(chain_id, &emitter_address) - .expect("Serialization should succeed"); + let actual_bytes = serialize_data_source_to_bytes(chain_id, &emitter_address); assert_eq!( actual_bytes, expected_bytes, From ab0b2a386052070470283eb902b2294108b225c4 Mon Sep 17 00:00:00 2001 From: Ayush Suresh Date: Wed, 9 Jul 2025 13:09:35 -0500 Subject: [PATCH 03/22] cleaned up test_data file usage --- .../pyth-receiver/src/integration_tests.rs | 87 +++---------------- .../contracts/pyth-receiver/src/structs.rs | 1 - .../contracts/pyth-receiver/src/test_data.rs | 68 +++++++++++++++ 3 files changed, 79 insertions(+), 77 deletions(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs index 9e6131146b..9cffae0bb7 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs @@ -1,9 +1,10 @@ #[cfg(test)] mod test { - use crate::error::PythReceiverError; - use crate::test_data; + use crate::{error::PythReceiverError}; + use crate::test_data::{self, good_update2_results, multiple_updates_results}; + use crate::test_data::good_update1_results; use crate::PythReceiver; - use alloy_primitives::{address, Address, I32, I64, U256, U64}; + use alloy_primitives::{Address, U256}; use motsu::prelude::*; use pythnet_sdk::wire::v1::{AccumulatorUpdateData, Proof}; use wormhole_contract::WormholeContract; @@ -12,13 +13,7 @@ mod test { 0xdb, 0x33, 0x0f, 0x7a, 0xc6, 0x6b, 0x72, 0xdc, 0x65, 0x8a, 0xfe, 0xdf, 0x0f, 0x4a, 0x41, 0x5b, 0x43, ]; - const TEST_PUBLISH_TIME: u64 = 1751563000; - const TEST_PRICE: i64 = 10967241867779; - const TEST_CONF: u64 = 4971244966; - const TEST_EXPO: i32 = -8; - const TEST_EMA_PRICE: i64 = 10942391100000; - const TEST_EMA_CONF: u64 = 4398561400; - + const PYTHNET_CHAIN_ID: u16 = 26; const PYTHNET_EMITTER_ADDRESS: [u8; 32] = [ 0xe1, 0x01, 0xfa, 0xed, 0xac, 0x58, 0x51, 0xe3, 0x2b, 0x9b, 0x23, 0xb5, 0xf9, 0x41, 0x1a, @@ -32,31 +27,6 @@ mod test { const SINGLE_UPDATE_FEE_IN_WEI: U256 = U256::from_limbs([100, 0, 0, 0]); - #[cfg(test)] - fn current_guardians() -> Vec
{ - vec![ - address!("0x5893B5A76c3f739645648885bDCcC06cd70a3Cd3"), // Rockaway - address!("0xfF6CB952589BDE862c25Ef4392132fb9D4A42157"), // Staked - address!("0x114De8460193bdf3A2fCf81f86a09765F4762fD1"), // Figment - address!("0x107A0086b32d7A0977926A205131d8731D39cbEB"), // ChainodeTech - address!("0x8C82B2fd82FaeD2711d59AF0F2499D16e726f6b2"), // Inotel - address!("0x11b39756C042441BE6D8650b69b54EbE715E2343"), // HashKey Cloud - address!("0x54Ce5B4D348fb74B958e8966e2ec3dBd4958a7cd"), // ChainLayer - address!("0x15e7cAF07C4e3DC8e7C469f92C8Cd88FB8005a20"), // xLabs - address!("0x74a3bf913953D695260D88BC1aA25A4eeE363ef0"), // Forbole - address!("0x000aC0076727b35FBea2dAc28fEE5cCB0fEA768e"), // Staking Fund - address!("0xAF45Ced136b9D9e24903464AE889F5C8a723FC14"), // Moonlet Wallet - address!("0xf93124b7c738843CBB89E864c862c38cddCccF95"), // P2P Validator - address!("0xD2CC37A4dc036a8D232b48f62cDD4731412f4890"), // 01node - address!("0xDA798F6896A3331F64b48c12D1D57Fd9cbe70811"), // MCF - address!("0x71AA1BE1D36CaFE3867910F99C09e347899C19C3"), // Everstake - address!("0x8192b6E7387CCd768277c17DAb1b7a5027c0b3Cf"), // Chorus One - address!("0x178e21ad2E77AE06711549CFBB1f9c7a9d8096e8"), // Syncnode - address!("0x5E1487F35515d02A92753504a8D75471b9f49EdB"), // Triton - address!("0x6FbEBc898F403E4773E95feB15E80C9A99c8348d"), // Staking Facilities - ] - } - #[cfg(test)] fn mock_get_update_fee(update_data: Vec) -> Result { let update_data_array: &[u8] = &update_data; @@ -77,7 +47,7 @@ mod test { wormhole_contract: &Contract, alice: &Address, ) { - let guardians = current_guardians(); + let guardians = test_data::current_guardians(); let governance_contract = Address::from_slice(&GOVERNANCE_CONTRACT.to_be_bytes::<32>()[12..32]); wormhole_contract @@ -137,14 +107,7 @@ mod test { assert!(price_result.is_ok()); assert_eq!( price_result.unwrap(), - ( - U64::from(TEST_PUBLISH_TIME), - I32::from_le_bytes(TEST_EXPO.to_le_bytes()), - I64::from_le_bytes(TEST_PRICE.to_le_bytes()), - U64::from(TEST_CONF), - I64::from_le_bytes(TEST_EMA_PRICE.to_le_bytes()), - U64::from(TEST_EMA_CONF) - ) + good_update1_results() ); } @@ -198,14 +161,7 @@ mod test { assert!(price_result.is_ok()); assert_eq!( price_result.unwrap(), - ( - U64::from(1751573860u64), - I32::from_le_bytes((-8i32).to_le_bytes()), - I64::from_le_bytes(10985663592646i64.to_le_bytes()), - U64::from(4569386330u64), - I64::from_le_bytes(10977795800000i64.to_le_bytes()), - U64::from(3919318300u64) - ) + good_update2_results() ); } @@ -273,14 +229,7 @@ mod test { assert!(price_result.is_ok()); assert_eq!( price_result.unwrap(), - ( - U64::from(1751573860u64), - I32::from_le_bytes((-8i32).to_le_bytes()), - I64::from_le_bytes(10985663592646i64.to_le_bytes()), - U64::from(4569386330u64), - I64::from_le_bytes(10977795800000i64.to_le_bytes()), - U64::from(3919318300u64) - ) + good_update2_results() ); } @@ -345,28 +294,14 @@ mod test { assert!(first_price_result.is_ok()); assert_eq!( first_price_result.unwrap(), - ( - U64::from(1751573123u64), - I32::from_le_bytes((-8i32).to_le_bytes()), - I64::from_le_bytes(10990356724259i64.to_le_bytes()), - U64::from(3891724259u64), - I64::from_le_bytes(10974970400000i64.to_le_bytes()), - U64::from(3918344000u64) - ) + multiple_updates_results()[0] ); let second_price_result = pyth_contract.sender(alice).get_price_unsafe(second_id); assert!(second_price_result.is_ok()); assert_eq!( second_price_result.unwrap(), - ( - U64::from(1751573123u64), - I32::from_le_bytes((-8i32).to_le_bytes()), - I64::from_le_bytes(258906787480i64.to_le_bytes()), - U64::from(158498649u64), - I64::from_le_bytes(258597182000i64.to_le_bytes()), - U64::from(131285914u64) - ) + multiple_updates_results()[1] ); } } diff --git a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs b/target_chains/stylus/contracts/pyth-receiver/src/structs.rs index abfcfd7d77..504619ae4c 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/structs.rs @@ -1,5 +1,4 @@ use alloc::{vec::Vec}; -use serde::Serialize; use stylus_sdk::alloy_primitives::{keccak256, FixedBytes, B256, I32, I64, U16, U256, U64}; use stylus_sdk::{ prelude::*, diff --git a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs index 07aac6deb1..c9c7708ee6 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs @@ -1,4 +1,5 @@ use hex::FromHex; +use alloy_primitives::{I32, I64, U64, address, Address}; pub fn good_update1() -> Vec { let hex_str = "504e41550100000003b801000000040d0216f3809b6396fdb0708bc94515ddb96a3bc8fb1993916e74f522ab4c34a268836a0bb38786303b55cc40ecb50d18c92bf9fd61688a143f3d24a73a3f468e4ab0000365be4f3a330fe96bab246922d9fa4816a865dec40d7c522e37f7e3605673b8f52eb30a4dad7aee3e1ac4b21337b8831c6147ef6e359e843b307872e83b5c7fe80004b6f12766eb395d04bdb146b1b69a4b9a8831a9c9ea20ee841d55efe72c629aef17038b925584493af7882981260b09587d73b6463415f4e1f8fb0a2a2c959c8301065c18a776cf558e43494bf31dd26ac0e3aed07a01ca0063abcfca3736b892368e4bf8b957f2d2e83ff9eb3fa8f667ef97a5f48c286103f70fda4a72e077719a0200085896c930febfb864a8c292bde679092e386e53389cb2d26bd12ceed64d22c0cd27676dc5c46d3e3c5949abbce89d4cc5ec378cfbf9ab1b0c24cfeb3371df4864000a1c67e67adea9f8a71eee76765f1fe4c7d9539d21b62d0336513692897cc6acbe1c827599a1f8c73b7478e8d788443b4cfd4e373344ab1ac9f771c9c494124863000b7e08e1cc1291340e6ec7d1b04c6a9c63f74077a074ee68edf4f95cf24c9743620f8abc8213884c8e4848fb76ec319d365e0cdc746a6e534a4cb828e51719be79010c61a2fedeedf34e4c80624d80cb93e24bafe9f6d23339173004d84e61c2395bfb5f552e87b901beb192ba6f4fc905eae30317c52b8614071e08a265592f24e8de000de38d08612edc5ebc863ea5a96325cb991750a94ff0e50f86bc322cce81db7cd17cb4ed3703f7477eb111a9d881e1345f5b79d618814f31b46034196563ee6a18000e5b11510d585a2decaba0be9e71386865b6069061478f7254d7852d55116569eb426c385267e40264d16db08e0f1a9e2c44b7d1c926d3c3ba662b212572386483010fa1ad0278402104b146b6f4d1cf85ac4df961d24eea0c7948b700f9973596cad130abfff25feef37125ba38507f34308d967455651e7014e40264a0c6510d3af001101f2e4e70868d6c327c92229537f1ffa33e488da3140ccc086f8210b437b162190742bd01ad1cb495a93f20045b4bb47e1562fdd82a8a1548d87d788a492b17190111847f5095df3edefc58be0956aee19876e850516e132506fd67504afee3c8cf240f07fb607b3c8282a2e56dcad23959e6759bdf8ad345ba8150448da56ff34fcc016866baf800000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71000000000880cea9014155575600000000000d8e5c8d0000271085e6ab1bb044f57c4cd6c1d32aa0a82a5032198301005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009f9828e420300000001284f2da6fffffff8000000006866baf8000000006866baf8000009f3b955a26000000001062cb8780c1283a49180b4986f0dec3c746d3daeb597887747b8f66a09876e1253a1ebb8a6bc4a5793daaa343db6057b82ec29715d7e1db0ffd6db523f7b80b03e3866ef5f5c80728801b92f5acecc28d8517e5615335d89c553f94b4370f3a20be0bc23e0fd401c4e5bd8bd32948a26233fc48f116428a490f087030ccfc442753e3074e2b9bbc1c61a009d86aaa200645c627a6b7f2f6597e34c60b14a58ef2583bcbb1d0e21b71a264fad2648ecc545031c7ed598772ffe875bf94a488389a49e6025e1b2a1f07ec598d0d9aa8ef7dd2733c8502c49d1d1323f1ae664e82e8a5e14978d52ab448ba9b1afc78f06c8cd17415a17"; @@ -6,6 +7,49 @@ pub fn good_update1() -> Vec { bytes } +pub fn good_update1_results() -> (U64, I32, I64, U64, I64, U64) { + ( + U64::from(1751563000u64), + I32::from_le_bytes((-8i32).to_le_bytes()), + I64::from_le_bytes(10967241867779i64.to_le_bytes()), + U64::from(4971244966u64), + I64::from_le_bytes(10942391100000i64.to_le_bytes()), + U64::from(4398561400u64) + ) +} + +pub fn multiple_updates_results() -> [(U64, I32, I64, U64, I64, U64); 2] { + [ + ( + U64::from(1751573123u64), + I32::from_le_bytes((-8i32).to_le_bytes()), + I64::from_le_bytes(10990356724259i64.to_le_bytes()), + U64::from(3891724259u64), + I64::from_le_bytes(10974970400000i64.to_le_bytes()), + U64::from(3918344000u64) + ), + ( + U64::from(1751573123u64), + I32::from_le_bytes((-8i32).to_le_bytes()), + I64::from_le_bytes(258906787480i64.to_le_bytes()), + U64::from(158498649u64), + I64::from_le_bytes(258597182000i64.to_le_bytes()), + U64::from(131285914u64) + ) + ] +} + +pub fn good_update2_results() -> (U64, I32, I64, U64, I64, U64) { + ( + U64::from(1751573860u64), + I32::from_le_bytes((-8i32).to_le_bytes()), + I64::from_le_bytes(10985663592646i64.to_le_bytes()), + U64::from(4569386330u64), + I64::from_le_bytes(10977795800000i64.to_le_bytes()), + U64::from(3919318300u64) + ) +} + pub fn good_update2() -> Vec { let hex_str = "504e41550100000003b801000000040d0239010392dab908eb9903d480abf8118d887f2a0c5eaeb9062e6eabab86c1b382127604c63358a7266cc5bade7726e159403c2bf317c7b3a4d8b489bfad4e334301031823d70352d3260226cbdddab0cf7d1584c0e1d23d4358ed12f9620e18a0db2154fbb096ac4cb8d5728e2cecf2b1398d7b9b51954f3fb8b4f59990ce017b0260000495e2691d8e6a0537d8ab3f41b5eb655acde7fbeaea0fdbe1f582383680f54c8a3a697c2c0f8b4110422f1b6beb0bfb601c929148b54dbf85fb19c333ccbb833c00066993a56c5980bf17d2790b933861fffb1fd09618921a90db4ab82cc8b148301f1a55d804d14cb39f648fdb0ef8c9ef1e24edc38d30f2aea7151025240a614bca0008a64a366c59bd6c4ce9d24a0e3beef2a33d28546826b1b969af184a257d648aab5672ad8a9eaf14473da40327e12e5c18168892bcebd693c8bed3df8ee50b85db010a36daa7c639c412969283f83749af93aef2464b27b83914b6026b721a59c8a04446a655686725247bd9154c71ca66505719df5867f775863a788d8bffb1bd637c000b237772560d72da81a782e89b138caf8bf1221b929ead77ca7d178b7b7af1c9141d9e77e22c98fe41b819f023695e6feed6f5215a5cdb6436bf52dc3c4c93e309010c89f2f3c64a8c77ccea47448e7871bbd70b59ed5761e5677458dbe6f82796efa2399e9ad9bf846d88d4688f1d19f9e2adeb2299017baf015c36a811d05c539b86000d6ba11d2f9a0edfd3a4bc23024d18dd010a83803faa79d40aec10a4deee40e8dd3c4c5401118b67bd6d879683cae3ea83d4f9afa744c655775615a7ce34237a02000e09a554d70c0f8e57bb79ce41552e38b836ad7b6bd1967e60c880f831341ad412699e4a9f5346713a6db2c7032bb7d1b3cc8e42f49ba17000f9d0916a13f2debf000f1ce88af88b96aaeb0104d4c966303eb9609df1b851a0d6149d05bba82f3fd70820a26d7f9d6fe18a7653fd3e3eda94fd9184726dadd2e8d58d09a8473e919f0800104583407293c41bef15c05ac20fc45fd5f9d00639c5b1f738d1ba42cd290fe5291e05219cefa8568806bfc1de76bcf5f799c90c9c6dd54bd69f9d459e994acb7a00110638c8067b42005ae678a7619e9eaad5fb66f0630547ab252179668e60b738c479ba6ff7e1f3dcffddab15e1bfebf93e0e4cb051535bdda3ecef6620aea32132016866e56400000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000008813690014155575600000000000d8ec4750000271098d4f856e398eb41afbd0f2b24ad80e58b1f57b601005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009fdcc9378c600000001105b4d5afffffff8000000006866e564000000006866e564000009fbf79e7bc000000000e99c0d1c0c02b95abadee324fbb6534576de1507c74c8ddef2b928c314cb3d4978a5ada03db907df05ba0fc051e659facec6479c324c276e5098fde9dcae0b462cd32d9e2e5b617b51ced85d38a8456022f3ab370d3c45a07acb686cfb39976b2f4bb1007a91e599951ed929f714a04dab0e6bd885a0c91a076f3b83ee8f765b70a3edda569876102f2c62cae15024e529a2e5e17c50411aa736c7511278a92f4d9cdda3239057c3a942a1365a58771734a982e41e1d7aa8bae87748f1becd045fcb5e1cb1993e978168147d6be8a2cba24a3cc8a2f78e7313f18c87ec2bb238510ebeb47aab50a449fd2ce3dc6b8c0d08d361c102"; let bytes = Vec::from_hex(hex_str).expect("Invalid hex string"); @@ -17,3 +61,27 @@ pub fn multiple_updates() -> Vec { let bytes = Vec::from_hex(hex_str).expect("Invalid hex string"); bytes } + +pub fn current_guardians() -> Vec
{ + vec![ + address!("0x5893B5A76c3f739645648885bDCcC06cd70a3Cd3"), // Rockaway + address!("0xfF6CB952589BDE862c25Ef4392132fb9D4A42157"), // Staked + address!("0x114De8460193bdf3A2fCf81f86a09765F4762fD1"), // Figment + address!("0x107A0086b32d7A0977926A205131d8731D39cbEB"), // ChainodeTech + address!("0x8C82B2fd82FaeD2711d59AF0F2499D16e726f6b2"), // Inotel + address!("0x11b39756C042441BE6D8650b69b54EbE715E2343"), // HashKey Cloud + address!("0x54Ce5B4D348fb74B958e8966e2ec3dBd4958a7cd"), // ChainLayer + address!("0x15e7cAF07C4e3DC8e7C469f92C8Cd88FB8005a20"), // xLabs + address!("0x74a3bf913953D695260D88BC1aA25A4eeE363ef0"), // Forbole + address!("0x000aC0076727b35FBea2dAc28fEE5cCB0fEA768e"), // Staking Fund + address!("0xAF45Ced136b9D9e24903464AE889F5C8a723FC14"), // Moonlet Wallet + address!("0xf93124b7c738843CBB89E864c862c38cddCccF95"), // P2P Validator + address!("0xD2CC37A4dc036a8D232b48f62cDD4731412f4890"), // 01node + address!("0xDA798F6896A3331F64b48c12D1D57Fd9cbe70811"), // MCF + address!("0x71AA1BE1D36CaFE3867910F99C09e347899C19C3"), // Everstake + address!("0x8192b6E7387CCd768277c17DAb1b7a5027c0b3Cf"), // Chorus One + address!("0x178e21ad2E77AE06711549CFBB1f9c7a9d8096e8"), // Syncnode + address!("0x5E1487F35515d02A92753504a8D75471b9f49EdB"), // Triton + address!("0x6FbEBc898F403E4773E95feB15E80C9A99c8348d"), // Staking Facilities + ] +} From 3a559c05a4753b87b6f72abe80a29ae2014f3319 Mon Sep 17 00:00:00 2001 From: Ayush Suresh Date: Wed, 9 Jul 2025 14:15:00 -0500 Subject: [PATCH 04/22] fixed update and parse functions to take in a vector of vector of u8s to support multiple updates --- .../pyth-receiver/src/integration_tests.rs | 86 +++++++++---------- .../stylus/contracts/pyth-receiver/src/lib.rs | 52 +++++++---- .../contracts/pyth-receiver/src/structs.rs | 8 +- .../contracts/pyth-receiver/src/test_data.rs | 40 ++++----- 4 files changed, 96 insertions(+), 90 deletions(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs index 9cffae0bb7..19e959facb 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs @@ -1,8 +1,8 @@ #[cfg(test)] mod test { - use crate::{error::PythReceiverError}; - use crate::test_data::{self, good_update2_results, multiple_updates_results}; + use crate::error::PythReceiverError; use crate::test_data::good_update1_results; + use crate::test_data::{self, good_update2_results, multiple_updates_results}; use crate::PythReceiver; use alloy_primitives::{Address, U256}; use motsu::prelude::*; @@ -13,7 +13,7 @@ mod test { 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] = [ 0xe1, 0x01, 0xfa, 0xed, 0xac, 0x58, 0x51, 0xe3, 0x2b, 0x9b, 0x23, 0xb5, 0xf9, 0x41, 0x1a, @@ -26,19 +26,29 @@ mod test { const GOVERNANCE_CONTRACT: U256 = U256::from_limbs([4, 0, 0, 0]); const SINGLE_UPDATE_FEE_IN_WEI: U256 = U256::from_limbs([100, 0, 0, 0]); + const TRANSACTION_FEE_IN_WEI: U256 = U256::from_limbs([32, 0, 0, 0]); #[cfg(test)] - fn mock_get_update_fee(update_data: Vec) -> Result { - let update_data_array: &[u8] = &update_data; - let accumulator_update = AccumulatorUpdateData::try_from_slice(&update_data_array) - .map_err(|_| PythReceiverError::InvalidAccumulatorMessage)?; - match accumulator_update.proof { - Proof::WormholeMerkle { vaa: _, updates } => { - let num_updates = - u8::try_from(updates.len()).map_err(|_| PythReceiverError::TooManyUpdates)?; - Ok(U256::from(num_updates).saturating_mul(SINGLE_UPDATE_FEE_IN_WEI)) + fn mock_get_update_fee(update_data: Vec>) -> Result { + let mut total_num_updates: u64 = 0; + for data in &update_data { + let update_data_array: &[u8] = &data; + let accumulator_update = AccumulatorUpdateData::try_from_slice(&update_data_array) + .map_err(|_| PythReceiverError::InvalidAccumulatorMessage)?; + match accumulator_update.proof { + Proof::WormholeMerkle { vaa: _, updates } => { + let num_updates = u64::try_from(updates.len()) + .map_err(|_| PythReceiverError::TooManyUpdates)?; + total_num_updates += num_updates; + } } } + Ok(get_total_fee(total_num_updates)) + } + + fn get_total_fee(total_num_updates: u64) -> U256 { + U256::from(total_num_updates).saturating_mul(SINGLE_UPDATE_FEE_IN_WEI) + + TRANSACTION_FEE_IN_WEI } #[cfg(test)] @@ -93,11 +103,11 @@ mod test { ) { pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice); - alice.fund(U256::from(200)); - let update_data = test_data::good_update1(); 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); @@ -105,10 +115,7 @@ mod test { let price_result = pyth_contract.sender(alice).get_price_unsafe(TEST_PRICE_ID); assert!(price_result.is_ok()); - assert_eq!( - price_result.unwrap(), - good_update1_results() - ); + assert_eq!(price_result.unwrap(), good_update1_results()); } #[motsu::test] @@ -140,18 +147,19 @@ mod test { ) { pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice); - alice.fund(U256::from(200)); - let update_data1 = test_data::good_update1(); let update_fee1 = mock_get_update_fee(update_data1.clone()).unwrap(); + + let update_data2 = test_data::good_update2(); + let update_fee2 = mock_get_update_fee(update_data2.clone()).unwrap(); + + alice.fund(update_fee1 + update_fee2); + let result1 = pyth_contract .sender_and_value(alice, update_fee1) .update_price_feeds(update_data1); assert!(result1.is_ok()); - let update_data2 = test_data::good_update2(); - let update_fee2 = mock_get_update_fee(update_data2.clone()).unwrap(); - let result2 = pyth_contract .sender_and_value(alice, update_fee2) .update_price_feeds(update_data2); @@ -159,10 +167,7 @@ mod test { let price_result = pyth_contract.sender(alice).get_price_unsafe(TEST_PRICE_ID); assert!(price_result.is_ok()); - assert_eq!( - price_result.unwrap(), - good_update2_results() - ); + assert_eq!(price_result.unwrap(), good_update2_results()); } #[motsu::test] @@ -213,11 +218,11 @@ mod test { ) { pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice); - alice.fund(U256::from(200)); - let update_data = test_data::good_update2(); 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); @@ -227,10 +232,7 @@ mod test { .sender(alice) .get_price_no_older_than(TEST_PRICE_ID, u64::MAX); assert!(price_result.is_ok()); - assert_eq!( - price_result.unwrap(), - good_update2_results() - ); + assert_eq!(price_result.unwrap(), good_update2_results()); } #[motsu::test] @@ -241,11 +243,11 @@ mod test { ) { pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice); - alice.fund(U256::from(200)); - let update_data = test_data::good_update2(); 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); @@ -269,11 +271,11 @@ mod test { ) { pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice); - alice.fund(U256::from(200)); - let update_data = test_data::multiple_updates(); 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); @@ -292,16 +294,10 @@ mod test { 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_results()[0] - ); + assert_eq!(first_price_result.unwrap(), multiple_updates_results()[0]); let second_price_result = pyth_contract.sender(alice).get_price_unsafe(second_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_results()[1]); } } diff --git a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs index 3626e0aaaa..3ec35c650d 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs @@ -171,8 +171,21 @@ impl PythReceiver { } #[payable] - pub fn update_price_feeds(&mut self, update_data: Vec) -> Result<(), PythReceiverError> { - self.update_price_feeds_internal(update_data)?; + pub fn update_price_feeds( + &mut self, + update_data: Vec>, + ) -> Result<(), PythReceiverError> { + for data in &update_data { + self.update_price_feeds_internal(data.clone())?; + } + + let total_fee = self.get_update_fee(update_data)?; + + let value = self.vm().msg_value(); + + if value < total_fee { + return Err(PythReceiverError::InsufficientFee); + } Ok(()) } @@ -234,14 +247,6 @@ impl PythReceiver { let root_digest: MerkleRoot = parse_wormhole_proof(vaa)?; - let total_fee = self.get_update_fee(update_data)?; - - let value = self.vm().msg_value(); - - if value < total_fee { - return Err(PythReceiverError::InsufficientFee); - } - for update in updates { let message_vec = Vec::from(update.message); let proof: MerklePath = update.proof; @@ -294,17 +299,26 @@ impl PythReceiver { Ok(()) } - fn get_update_fee(&self, update_data: Vec) -> Result { - let update_data_array: &[u8] = &update_data; - let accumulator_update = AccumulatorUpdateData::try_from_slice(&update_data_array) - .map_err(|_| PythReceiverError::InvalidAccumulatorMessage)?; - match accumulator_update.proof { - Proof::WormholeMerkle { vaa: _, updates } => { - let num_updates = - u8::try_from(updates.len()).map_err(|_| PythReceiverError::TooManyUpdates)?; - Ok(U256::from(num_updates).saturating_mul(self.single_update_fee_in_wei.get())) + fn get_update_fee(&self, update_data: Vec>) -> Result { + let mut total_num_updates: u64 = 0; + for data in &update_data { + let update_data_array: &[u8] = &data; + let accumulator_update = AccumulatorUpdateData::try_from_slice(&update_data_array) + .map_err(|_| PythReceiverError::InvalidAccumulatorMessage)?; + match accumulator_update.proof { + Proof::WormholeMerkle { vaa: _, updates } => { + let num_updates = u64::try_from(updates.len()) + .map_err(|_| PythReceiverError::TooManyUpdates)?; + total_num_updates += num_updates; + } } } + Ok(self.get_total_fee(total_num_updates)) + } + + fn get_total_fee(&self, total_num_updates: u64) -> U256 { + 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>) -> U256 { diff --git a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs b/target_chains/stylus/contracts/pyth-receiver/src/structs.rs index 504619ae4c..13e419ca15 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/structs.rs @@ -1,21 +1,17 @@ -use alloc::{vec::Vec}; +use alloc::vec::Vec; use stylus_sdk::alloy_primitives::{keccak256, FixedBytes, B256, I32, I64, U16, U256, U64}; use stylus_sdk::{ prelude::*, storage::{StorageFixedBytes, StorageI32, StorageI64, StorageKey, StorageU16, StorageU64}, }; -fn serialize_data_source_to_bytes( - chain_id: u16, - emitter_address: &[u8; 32], -) -> [u8; 34] { +fn serialize_data_source_to_bytes(chain_id: u16, emitter_address: &[u8; 32]) -> [u8; 34] { let mut result = [0u8; 34]; result[0..2].copy_from_slice(&chain_id.to_be_bytes()); result[2..].copy_from_slice(emitter_address); result } - #[derive(Debug)] #[storage] pub struct DataSourceStorage { diff --git a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs index c9c7708ee6..aa8cecc655 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs @@ -1,10 +1,22 @@ +use alloy_primitives::{address, Address, I32, I64, U64}; use hex::FromHex; -use alloy_primitives::{I32, I64, U64, address, Address}; -pub fn good_update1() -> Vec { +pub fn good_update1() -> Vec> { let hex_str = "504e41550100000003b801000000040d0216f3809b6396fdb0708bc94515ddb96a3bc8fb1993916e74f522ab4c34a268836a0bb38786303b55cc40ecb50d18c92bf9fd61688a143f3d24a73a3f468e4ab0000365be4f3a330fe96bab246922d9fa4816a865dec40d7c522e37f7e3605673b8f52eb30a4dad7aee3e1ac4b21337b8831c6147ef6e359e843b307872e83b5c7fe80004b6f12766eb395d04bdb146b1b69a4b9a8831a9c9ea20ee841d55efe72c629aef17038b925584493af7882981260b09587d73b6463415f4e1f8fb0a2a2c959c8301065c18a776cf558e43494bf31dd26ac0e3aed07a01ca0063abcfca3736b892368e4bf8b957f2d2e83ff9eb3fa8f667ef97a5f48c286103f70fda4a72e077719a0200085896c930febfb864a8c292bde679092e386e53389cb2d26bd12ceed64d22c0cd27676dc5c46d3e3c5949abbce89d4cc5ec378cfbf9ab1b0c24cfeb3371df4864000a1c67e67adea9f8a71eee76765f1fe4c7d9539d21b62d0336513692897cc6acbe1c827599a1f8c73b7478e8d788443b4cfd4e373344ab1ac9f771c9c494124863000b7e08e1cc1291340e6ec7d1b04c6a9c63f74077a074ee68edf4f95cf24c9743620f8abc8213884c8e4848fb76ec319d365e0cdc746a6e534a4cb828e51719be79010c61a2fedeedf34e4c80624d80cb93e24bafe9f6d23339173004d84e61c2395bfb5f552e87b901beb192ba6f4fc905eae30317c52b8614071e08a265592f24e8de000de38d08612edc5ebc863ea5a96325cb991750a94ff0e50f86bc322cce81db7cd17cb4ed3703f7477eb111a9d881e1345f5b79d618814f31b46034196563ee6a18000e5b11510d585a2decaba0be9e71386865b6069061478f7254d7852d55116569eb426c385267e40264d16db08e0f1a9e2c44b7d1c926d3c3ba662b212572386483010fa1ad0278402104b146b6f4d1cf85ac4df961d24eea0c7948b700f9973596cad130abfff25feef37125ba38507f34308d967455651e7014e40264a0c6510d3af001101f2e4e70868d6c327c92229537f1ffa33e488da3140ccc086f8210b437b162190742bd01ad1cb495a93f20045b4bb47e1562fdd82a8a1548d87d788a492b17190111847f5095df3edefc58be0956aee19876e850516e132506fd67504afee3c8cf240f07fb607b3c8282a2e56dcad23959e6759bdf8ad345ba8150448da56ff34fcc016866baf800000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71000000000880cea9014155575600000000000d8e5c8d0000271085e6ab1bb044f57c4cd6c1d32aa0a82a5032198301005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009f9828e420300000001284f2da6fffffff8000000006866baf8000000006866baf8000009f3b955a26000000001062cb8780c1283a49180b4986f0dec3c746d3daeb597887747b8f66a09876e1253a1ebb8a6bc4a5793daaa343db6057b82ec29715d7e1db0ffd6db523f7b80b03e3866ef5f5c80728801b92f5acecc28d8517e5615335d89c553f94b4370f3a20be0bc23e0fd401c4e5bd8bd32948a26233fc48f116428a490f087030ccfc442753e3074e2b9bbc1c61a009d86aaa200645c627a6b7f2f6597e34c60b14a58ef2583bcbb1d0e21b71a264fad2648ecc545031c7ed598772ffe875bf94a488389a49e6025e1b2a1f07ec598d0d9aa8ef7dd2733c8502c49d1d1323f1ae664e82e8a5e14978d52ab448ba9b1afc78f06c8cd17415a17"; let bytes = Vec::from_hex(hex_str).expect("Invalid hex string"); - bytes + vec![bytes] +} + +pub fn good_update2() -> Vec> { + let hex_str = "504e41550100000003b801000000040d0239010392dab908eb9903d480abf8118d887f2a0c5eaeb9062e6eabab86c1b382127604c63358a7266cc5bade7726e159403c2bf317c7b3a4d8b489bfad4e334301031823d70352d3260226cbdddab0cf7d1584c0e1d23d4358ed12f9620e18a0db2154fbb096ac4cb8d5728e2cecf2b1398d7b9b51954f3fb8b4f59990ce017b0260000495e2691d8e6a0537d8ab3f41b5eb655acde7fbeaea0fdbe1f582383680f54c8a3a697c2c0f8b4110422f1b6beb0bfb601c929148b54dbf85fb19c333ccbb833c00066993a56c5980bf17d2790b933861fffb1fd09618921a90db4ab82cc8b148301f1a55d804d14cb39f648fdb0ef8c9ef1e24edc38d30f2aea7151025240a614bca0008a64a366c59bd6c4ce9d24a0e3beef2a33d28546826b1b969af184a257d648aab5672ad8a9eaf14473da40327e12e5c18168892bcebd693c8bed3df8ee50b85db010a36daa7c639c412969283f83749af93aef2464b27b83914b6026b721a59c8a04446a655686725247bd9154c71ca66505719df5867f775863a788d8bffb1bd637c000b237772560d72da81a782e89b138caf8bf1221b929ead77ca7d178b7b7af1c9141d9e77e22c98fe41b819f023695e6feed6f5215a5cdb6436bf52dc3c4c93e309010c89f2f3c64a8c77ccea47448e7871bbd70b59ed5761e5677458dbe6f82796efa2399e9ad9bf846d88d4688f1d19f9e2adeb2299017baf015c36a811d05c539b86000d6ba11d2f9a0edfd3a4bc23024d18dd010a83803faa79d40aec10a4deee40e8dd3c4c5401118b67bd6d879683cae3ea83d4f9afa744c655775615a7ce34237a02000e09a554d70c0f8e57bb79ce41552e38b836ad7b6bd1967e60c880f831341ad412699e4a9f5346713a6db2c7032bb7d1b3cc8e42f49ba17000f9d0916a13f2debf000f1ce88af88b96aaeb0104d4c966303eb9609df1b851a0d6149d05bba82f3fd70820a26d7f9d6fe18a7653fd3e3eda94fd9184726dadd2e8d58d09a8473e919f0800104583407293c41bef15c05ac20fc45fd5f9d00639c5b1f738d1ba42cd290fe5291e05219cefa8568806bfc1de76bcf5f799c90c9c6dd54bd69f9d459e994acb7a00110638c8067b42005ae678a7619e9eaad5fb66f0630547ab252179668e60b738c479ba6ff7e1f3dcffddab15e1bfebf93e0e4cb051535bdda3ecef6620aea32132016866e56400000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000008813690014155575600000000000d8ec4750000271098d4f856e398eb41afbd0f2b24ad80e58b1f57b601005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009fdcc9378c600000001105b4d5afffffff8000000006866e564000000006866e564000009fbf79e7bc000000000e99c0d1c0c02b95abadee324fbb6534576de1507c74c8ddef2b928c314cb3d4978a5ada03db907df05ba0fc051e659facec6479c324c276e5098fde9dcae0b462cd32d9e2e5b617b51ced85d38a8456022f3ab370d3c45a07acb686cfb39976b2f4bb1007a91e599951ed929f714a04dab0e6bd885a0c91a076f3b83ee8f765b70a3edda569876102f2c62cae15024e529a2e5e17c50411aa736c7511278a92f4d9cdda3239057c3a942a1365a58771734a982e41e1d7aa8bae87748f1becd045fcb5e1cb1993e978168147d6be8a2cba24a3cc8a2f78e7313f18c87ec2bb238510ebeb47aab50a449fd2ce3dc6b8c0d08d361c102"; + let bytes = Vec::from_hex(hex_str).expect("Invalid hex string"); + vec![bytes] +} + +pub fn multiple_updates() -> Vec> { + let hex_str = "504e41550100000003b801000000040d02e57b0f291daa4d2f02f5c4a18793b278b238338f472d17897f8f0866549f77571cfe71fa55bae7f340b9124511559b73a0cf01c72adc8a8d9963cebecc5a503801039507a96b155046ab039f7c9cad17a4927e2ff34763bca9b65d572ddc7a5f019832ffbeeb5295447bfdb989efa0314865bb4571770ad8e75ae7a083288d6de232010412e7333ab5cf0f20274b0907da43b52016d5a095bb846962d13a222e4af1e7e63f7a8db49de04feb70f07a0e274dc58acc7a4c386a099369412c6813ba39916100063da672f75cf1d397829a39461e311ca366366828be8d12b19a00c552e7c8c5e7746b36d97dccc54e5b3aeae188b372ec885dc1fbd9c2285ce458764c86f0c1bb0008863aa237e9fe339683992121249a2e520b6483a3b3b60c703a1eb09ef33266312e729ff6d398e1a60be8474a95803cd1641ef6c1de2c74f3cd7e1f2510c919f9000a3bd5ec58424b21c48552c3be0f9cccd6e6c641eee2b4e550fb88cc93cfdf10c7409344ec3e81df711a293baba565a85e620d20028d9738e53939fa52f19ce622010b000f803511f89f02610fbece34fe327afb55196cc3e522bb28d71d6e4d5523ac77ca1afbbd8a28b4fe05c7f2aa1c3f428c89fe21096ba67bc505cbfa6ead9808010c315b34c9cac03647df4e12a050f8b739763498aa23999244036e09010e2a79a46d0cbabc22c535542896bc22df05dc5480db06a370dffeb0814424870fd50c21000d4a562686000b65df4e0ca00d2e00d10db9e913b481337ee1c80bb47b25553afb693d7be0c17f6fb106909a1eed52a6c27739471b719d4c450b99b066a02bd2c9010e309508bc7128030ca4b19fc34c0ee0e62eebb549c759c2e8ccfdf062793e41e935754ae1d5356ba98446fa2eaa837ae4b413d1ccdf1af6d9060a2885f18c19e1010f3e2ff50704a6ad1b491cb93a1e4678c0f58b91540ba3ce3b4424c96abbe922562c924debb3336ab2fe835237f16912d768e6e5b739f2ab44b57a1e2607c9bb89001070d0dfac758a38342b107870b4d5761df9e785c6be589317c4b1dad3c08998f11214c29201d172b278aa6f4d57171f0f05fb7a2718e6da6df4449e8897c0c2ac0011d9e885989fa2363ec311bf4e9ebd8738d4b3ecaf9a31c09ce06f9876c3ab772034c1df9ca09c847ee81de80a1f0f8592019fa60e55b02b657b8a7c99bee04701016866e28300000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000008812f80014155575600000000000d8ebd6500002710f015dfd43b23aad91dcd4a7a8a113ed2d39233f202005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009fee44efa2300000000e7f6ffe3fffffff8000000006866e283000000006866e283000009fb4f364d0000000000e98d2f400c2704dab60f1b310d567acb60d77a3ce8003a6f564e8e1f567f00f004381d755e160a07372977a99288dcc9c9477cf9c1bb095403b514082aa774f7b243003e30548cbd97e8191d5ef2732796e06f84f05543a171f1e66052aa515c41a2d994a0d13e2e4016e6a28823201a52d408a5024797ec4b7629406062dd9ccc30a5d1eb4ac8b4a28a3d464bf4335ceda7646e03c29cc24b6c7c5e5924e6e69400a2c90561c9a2e4555084af13fbc7eaa0a884b75d4d1197933ac174b62c4b9b1cde3dd496f5e54cd2e01cdca0ba5c5a80a2bbd0d9d5dfb7aab5b638ef883e4e55f78a1536fe79c5c3e16cda9b53e364e3bbe95f005500ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace0000003c480c0e980000000009727f59fffffff8000000006866e283000000006866e2830000003c3597da300000000007d3439a0ccf5f10d7559e184107e994663aa0fc8f81718c0b281162b77eb09c774da30e2db5674df62494b3da820f6c986a0f32d1a195b6bc4676891d4e28cdb4e2f09dd47db3243547b37bdbb9799c82a42d6f1f18f8e17d7bed68408ef26e184f21e9b640e2c9f0416d91987acbe6fa8e72c2c99fa548f83c0eb5dd3c269ef52101521ef0b3d26f50b07dae68311bd138338881b20b78f8d21d2bfc27e9ac849b4c659d61c9a2e4555084af13fbc7eaa0a884b75d4d1197933ac174b62c4b9b1cde3dd496f5e54cd2e01cdca0ba5c5a80a2bbd0d9d5dfb7aab5b638ef883e4e55f78a1536fe79c5c3e16cda9b53e364e3bbe95f"; + let bytes = Vec::from_hex(hex_str).expect("Invalid hex string"); + vec![bytes] } pub fn good_update1_results() -> (U64, I32, I64, U64, I64, U64) { @@ -14,7 +26,7 @@ pub fn good_update1_results() -> (U64, I32, I64, U64, I64, U64) { I64::from_le_bytes(10967241867779i64.to_le_bytes()), U64::from(4971244966u64), I64::from_le_bytes(10942391100000i64.to_le_bytes()), - U64::from(4398561400u64) + U64::from(4398561400u64), ) } @@ -26,7 +38,7 @@ pub fn multiple_updates_results() -> [(U64, I32, I64, U64, I64, U64); 2] { I64::from_le_bytes(10990356724259i64.to_le_bytes()), U64::from(3891724259u64), I64::from_le_bytes(10974970400000i64.to_le_bytes()), - U64::from(3918344000u64) + U64::from(3918344000u64), ), ( U64::from(1751573123u64), @@ -34,8 +46,8 @@ pub fn multiple_updates_results() -> [(U64, I32, I64, U64, I64, U64); 2] { I64::from_le_bytes(258906787480i64.to_le_bytes()), U64::from(158498649u64), I64::from_le_bytes(258597182000i64.to_le_bytes()), - U64::from(131285914u64) - ) + U64::from(131285914u64), + ), ] } @@ -46,22 +58,10 @@ pub fn good_update2_results() -> (U64, I32, I64, U64, I64, U64) { I64::from_le_bytes(10985663592646i64.to_le_bytes()), U64::from(4569386330u64), I64::from_le_bytes(10977795800000i64.to_le_bytes()), - U64::from(3919318300u64) + U64::from(3919318300u64), ) } -pub fn good_update2() -> Vec { - let hex_str = "504e41550100000003b801000000040d0239010392dab908eb9903d480abf8118d887f2a0c5eaeb9062e6eabab86c1b382127604c63358a7266cc5bade7726e159403c2bf317c7b3a4d8b489bfad4e334301031823d70352d3260226cbdddab0cf7d1584c0e1d23d4358ed12f9620e18a0db2154fbb096ac4cb8d5728e2cecf2b1398d7b9b51954f3fb8b4f59990ce017b0260000495e2691d8e6a0537d8ab3f41b5eb655acde7fbeaea0fdbe1f582383680f54c8a3a697c2c0f8b4110422f1b6beb0bfb601c929148b54dbf85fb19c333ccbb833c00066993a56c5980bf17d2790b933861fffb1fd09618921a90db4ab82cc8b148301f1a55d804d14cb39f648fdb0ef8c9ef1e24edc38d30f2aea7151025240a614bca0008a64a366c59bd6c4ce9d24a0e3beef2a33d28546826b1b969af184a257d648aab5672ad8a9eaf14473da40327e12e5c18168892bcebd693c8bed3df8ee50b85db010a36daa7c639c412969283f83749af93aef2464b27b83914b6026b721a59c8a04446a655686725247bd9154c71ca66505719df5867f775863a788d8bffb1bd637c000b237772560d72da81a782e89b138caf8bf1221b929ead77ca7d178b7b7af1c9141d9e77e22c98fe41b819f023695e6feed6f5215a5cdb6436bf52dc3c4c93e309010c89f2f3c64a8c77ccea47448e7871bbd70b59ed5761e5677458dbe6f82796efa2399e9ad9bf846d88d4688f1d19f9e2adeb2299017baf015c36a811d05c539b86000d6ba11d2f9a0edfd3a4bc23024d18dd010a83803faa79d40aec10a4deee40e8dd3c4c5401118b67bd6d879683cae3ea83d4f9afa744c655775615a7ce34237a02000e09a554d70c0f8e57bb79ce41552e38b836ad7b6bd1967e60c880f831341ad412699e4a9f5346713a6db2c7032bb7d1b3cc8e42f49ba17000f9d0916a13f2debf000f1ce88af88b96aaeb0104d4c966303eb9609df1b851a0d6149d05bba82f3fd70820a26d7f9d6fe18a7653fd3e3eda94fd9184726dadd2e8d58d09a8473e919f0800104583407293c41bef15c05ac20fc45fd5f9d00639c5b1f738d1ba42cd290fe5291e05219cefa8568806bfc1de76bcf5f799c90c9c6dd54bd69f9d459e994acb7a00110638c8067b42005ae678a7619e9eaad5fb66f0630547ab252179668e60b738c479ba6ff7e1f3dcffddab15e1bfebf93e0e4cb051535bdda3ecef6620aea32132016866e56400000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000008813690014155575600000000000d8ec4750000271098d4f856e398eb41afbd0f2b24ad80e58b1f57b601005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009fdcc9378c600000001105b4d5afffffff8000000006866e564000000006866e564000009fbf79e7bc000000000e99c0d1c0c02b95abadee324fbb6534576de1507c74c8ddef2b928c314cb3d4978a5ada03db907df05ba0fc051e659facec6479c324c276e5098fde9dcae0b462cd32d9e2e5b617b51ced85d38a8456022f3ab370d3c45a07acb686cfb39976b2f4bb1007a91e599951ed929f714a04dab0e6bd885a0c91a076f3b83ee8f765b70a3edda569876102f2c62cae15024e529a2e5e17c50411aa736c7511278a92f4d9cdda3239057c3a942a1365a58771734a982e41e1d7aa8bae87748f1becd045fcb5e1cb1993e978168147d6be8a2cba24a3cc8a2f78e7313f18c87ec2bb238510ebeb47aab50a449fd2ce3dc6b8c0d08d361c102"; - let bytes = Vec::from_hex(hex_str).expect("Invalid hex string"); - bytes -} - -pub fn multiple_updates() -> Vec { - let hex_str = "504e41550100000003b801000000040d02e57b0f291daa4d2f02f5c4a18793b278b238338f472d17897f8f0866549f77571cfe71fa55bae7f340b9124511559b73a0cf01c72adc8a8d9963cebecc5a503801039507a96b155046ab039f7c9cad17a4927e2ff34763bca9b65d572ddc7a5f019832ffbeeb5295447bfdb989efa0314865bb4571770ad8e75ae7a083288d6de232010412e7333ab5cf0f20274b0907da43b52016d5a095bb846962d13a222e4af1e7e63f7a8db49de04feb70f07a0e274dc58acc7a4c386a099369412c6813ba39916100063da672f75cf1d397829a39461e311ca366366828be8d12b19a00c552e7c8c5e7746b36d97dccc54e5b3aeae188b372ec885dc1fbd9c2285ce458764c86f0c1bb0008863aa237e9fe339683992121249a2e520b6483a3b3b60c703a1eb09ef33266312e729ff6d398e1a60be8474a95803cd1641ef6c1de2c74f3cd7e1f2510c919f9000a3bd5ec58424b21c48552c3be0f9cccd6e6c641eee2b4e550fb88cc93cfdf10c7409344ec3e81df711a293baba565a85e620d20028d9738e53939fa52f19ce622010b000f803511f89f02610fbece34fe327afb55196cc3e522bb28d71d6e4d5523ac77ca1afbbd8a28b4fe05c7f2aa1c3f428c89fe21096ba67bc505cbfa6ead9808010c315b34c9cac03647df4e12a050f8b739763498aa23999244036e09010e2a79a46d0cbabc22c535542896bc22df05dc5480db06a370dffeb0814424870fd50c21000d4a562686000b65df4e0ca00d2e00d10db9e913b481337ee1c80bb47b25553afb693d7be0c17f6fb106909a1eed52a6c27739471b719d4c450b99b066a02bd2c9010e309508bc7128030ca4b19fc34c0ee0e62eebb549c759c2e8ccfdf062793e41e935754ae1d5356ba98446fa2eaa837ae4b413d1ccdf1af6d9060a2885f18c19e1010f3e2ff50704a6ad1b491cb93a1e4678c0f58b91540ba3ce3b4424c96abbe922562c924debb3336ab2fe835237f16912d768e6e5b739f2ab44b57a1e2607c9bb89001070d0dfac758a38342b107870b4d5761df9e785c6be589317c4b1dad3c08998f11214c29201d172b278aa6f4d57171f0f05fb7a2718e6da6df4449e8897c0c2ac0011d9e885989fa2363ec311bf4e9ebd8738d4b3ecaf9a31c09ce06f9876c3ab772034c1df9ca09c847ee81de80a1f0f8592019fa60e55b02b657b8a7c99bee04701016866e28300000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000008812f80014155575600000000000d8ebd6500002710f015dfd43b23aad91dcd4a7a8a113ed2d39233f202005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009fee44efa2300000000e7f6ffe3fffffff8000000006866e283000000006866e283000009fb4f364d0000000000e98d2f400c2704dab60f1b310d567acb60d77a3ce8003a6f564e8e1f567f00f004381d755e160a07372977a99288dcc9c9477cf9c1bb095403b514082aa774f7b243003e30548cbd97e8191d5ef2732796e06f84f05543a171f1e66052aa515c41a2d994a0d13e2e4016e6a28823201a52d408a5024797ec4b7629406062dd9ccc30a5d1eb4ac8b4a28a3d464bf4335ceda7646e03c29cc24b6c7c5e5924e6e69400a2c90561c9a2e4555084af13fbc7eaa0a884b75d4d1197933ac174b62c4b9b1cde3dd496f5e54cd2e01cdca0ba5c5a80a2bbd0d9d5dfb7aab5b638ef883e4e55f78a1536fe79c5c3e16cda9b53e364e3bbe95f005500ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace0000003c480c0e980000000009727f59fffffff8000000006866e283000000006866e2830000003c3597da300000000007d3439a0ccf5f10d7559e184107e994663aa0fc8f81718c0b281162b77eb09c774da30e2db5674df62494b3da820f6c986a0f32d1a195b6bc4676891d4e28cdb4e2f09dd47db3243547b37bdbb9799c82a42d6f1f18f8e17d7bed68408ef26e184f21e9b640e2c9f0416d91987acbe6fa8e72c2c99fa548f83c0eb5dd3c269ef52101521ef0b3d26f50b07dae68311bd138338881b20b78f8d21d2bfc27e9ac849b4c659d61c9a2e4555084af13fbc7eaa0a884b75d4d1197933ac174b62c4b9b1cde3dd496f5e54cd2e01cdca0ba5c5a80a2bbd0d9d5dfb7aab5b638ef883e4e55f78a1536fe79c5c3e16cda9b53e364e3bbe95f"; - let bytes = Vec::from_hex(hex_str).expect("Invalid hex string"); - bytes -} - pub fn current_guardians() -> Vec
{ vec![ address!("0x5893B5A76c3f739645648885bDCcC06cd70a3Cd3"), // Rockaway From 7f6afc97fa5b12ba359a3936296d22940a0696d9 Mon Sep 17 00:00:00 2001 From: Ayush Suresh Date: Wed, 9 Jul 2025 16:21:21 -0500 Subject: [PATCH 05/22] added test to verify multiple updates configured --- .../pyth-receiver/src/integration_tests.rs | 63 +++++++++++++++---- .../contracts/pyth-receiver/src/test_data.rs | 33 +++++++++- 2 files changed, 83 insertions(+), 13 deletions(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs index 19e959facb..fb52702721 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs @@ -1,8 +1,7 @@ #[cfg(test)] mod test { use crate::error::PythReceiverError; - use crate::test_data::good_update1_results; - use crate::test_data::{self, good_update2_results, multiple_updates_results}; + use crate::test_data::*; use crate::PythReceiver; use alloy_primitives::{Address, U256}; use motsu::prelude::*; @@ -57,7 +56,7 @@ mod test { wormhole_contract: &Contract, alice: &Address, ) { - let guardians = test_data::current_guardians(); + let guardians = current_guardians(); let governance_contract = Address::from_slice(&GOVERNANCE_CONTRACT.to_be_bytes::<32>()[12..32]); wormhole_contract @@ -103,7 +102,7 @@ mod test { ) { pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice); - let update_data = test_data::good_update1(); + let update_data = good_update1(); let update_fee = mock_get_update_fee(update_data.clone()).unwrap(); alice.fund(update_fee); @@ -128,7 +127,7 @@ mod test { alice.fund(U256::from(200)); - let update_data = test_data::good_update1(); + let update_data = good_update1(); let update_fee = mock_get_update_fee(update_data.clone()).unwrap(); let small_update_fee = update_fee / U256::from(2); @@ -140,17 +139,17 @@ mod test { } #[motsu::test] - fn test_get_price_after_multiple_updates_returns_recent_price( + fn test_get_price_after_multiple_different_updates_returns_recent_price( pyth_contract: Contract, wormhole_contract: Contract, alice: Address, ) { pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice); - let update_data1 = test_data::good_update1(); + let update_data1 = good_update1(); let update_fee1 = mock_get_update_fee(update_data1.clone()).unwrap(); - let update_data2 = test_data::good_update2(); + let update_data2 = good_update2(); let update_fee2 = mock_get_update_fee(update_data2.clone()).unwrap(); alice.fund(update_fee1 + update_fee2); @@ -218,7 +217,7 @@ mod test { ) { pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice); - let update_data = test_data::good_update2(); + let update_data = good_update2(); let update_fee = mock_get_update_fee(update_data.clone()).unwrap(); alice.fund(update_fee); @@ -243,7 +242,7 @@ mod test { ) { pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice); - let update_data = test_data::good_update2(); + let update_data = good_update2(); let update_fee = mock_get_update_fee(update_data.clone()).unwrap(); alice.fund(update_fee); @@ -264,14 +263,14 @@ mod test { } #[motsu::test] - fn test_multiple_updates_different_ids_updates_both( + fn test_multiple_updates_in_same_vaa_different_ids_updates_both( pyth_contract: Contract, wormhole_contract: Contract, alice: Address, ) { pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice); - let update_data = test_data::multiple_updates(); + let update_data = multiple_updates_same_vaa(); let update_fee = mock_get_update_fee(update_data.clone()).unwrap(); alice.fund(update_fee); @@ -300,4 +299,44 @@ mod test { assert!(second_price_result.is_ok()); assert_eq!(second_price_result.unwrap(), multiple_updates_results()[1]); } + + #[motsu::test] + fn test_multiple_updates_different_ids_updates_both( + pyth_contract: Contract, + wormhole_contract: Contract, + 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 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; + + 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] + ); + + let second_price_result = pyth_contract.sender(alice).get_price_unsafe(second_id); + assert!(second_price_result.is_ok()); + assert_eq!( + second_price_result.unwrap(), + multiple_updates_diff_vaa_results()[1] + ); + } } diff --git a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs index aa8cecc655..29d2ea8c9f 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs @@ -1,5 +1,6 @@ use alloy_primitives::{address, Address, I32, I64, U64}; use hex::FromHex; +use std::vec; pub fn good_update1() -> Vec> { let hex_str = "504e41550100000003b801000000040d0216f3809b6396fdb0708bc94515ddb96a3bc8fb1993916e74f522ab4c34a268836a0bb38786303b55cc40ecb50d18c92bf9fd61688a143f3d24a73a3f468e4ab0000365be4f3a330fe96bab246922d9fa4816a865dec40d7c522e37f7e3605673b8f52eb30a4dad7aee3e1ac4b21337b8831c6147ef6e359e843b307872e83b5c7fe80004b6f12766eb395d04bdb146b1b69a4b9a8831a9c9ea20ee841d55efe72c629aef17038b925584493af7882981260b09587d73b6463415f4e1f8fb0a2a2c959c8301065c18a776cf558e43494bf31dd26ac0e3aed07a01ca0063abcfca3736b892368e4bf8b957f2d2e83ff9eb3fa8f667ef97a5f48c286103f70fda4a72e077719a0200085896c930febfb864a8c292bde679092e386e53389cb2d26bd12ceed64d22c0cd27676dc5c46d3e3c5949abbce89d4cc5ec378cfbf9ab1b0c24cfeb3371df4864000a1c67e67adea9f8a71eee76765f1fe4c7d9539d21b62d0336513692897cc6acbe1c827599a1f8c73b7478e8d788443b4cfd4e373344ab1ac9f771c9c494124863000b7e08e1cc1291340e6ec7d1b04c6a9c63f74077a074ee68edf4f95cf24c9743620f8abc8213884c8e4848fb76ec319d365e0cdc746a6e534a4cb828e51719be79010c61a2fedeedf34e4c80624d80cb93e24bafe9f6d23339173004d84e61c2395bfb5f552e87b901beb192ba6f4fc905eae30317c52b8614071e08a265592f24e8de000de38d08612edc5ebc863ea5a96325cb991750a94ff0e50f86bc322cce81db7cd17cb4ed3703f7477eb111a9d881e1345f5b79d618814f31b46034196563ee6a18000e5b11510d585a2decaba0be9e71386865b6069061478f7254d7852d55116569eb426c385267e40264d16db08e0f1a9e2c44b7d1c926d3c3ba662b212572386483010fa1ad0278402104b146b6f4d1cf85ac4df961d24eea0c7948b700f9973596cad130abfff25feef37125ba38507f34308d967455651e7014e40264a0c6510d3af001101f2e4e70868d6c327c92229537f1ffa33e488da3140ccc086f8210b437b162190742bd01ad1cb495a93f20045b4bb47e1562fdd82a8a1548d87d788a492b17190111847f5095df3edefc58be0956aee19876e850516e132506fd67504afee3c8cf240f07fb607b3c8282a2e56dcad23959e6759bdf8ad345ba8150448da56ff34fcc016866baf800000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71000000000880cea9014155575600000000000d8e5c8d0000271085e6ab1bb044f57c4cd6c1d32aa0a82a5032198301005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009f9828e420300000001284f2da6fffffff8000000006866baf8000000006866baf8000009f3b955a26000000001062cb8780c1283a49180b4986f0dec3c746d3daeb597887747b8f66a09876e1253a1ebb8a6bc4a5793daaa343db6057b82ec29715d7e1db0ffd6db523f7b80b03e3866ef5f5c80728801b92f5acecc28d8517e5615335d89c553f94b4370f3a20be0bc23e0fd401c4e5bd8bd32948a26233fc48f116428a490f087030ccfc442753e3074e2b9bbc1c61a009d86aaa200645c627a6b7f2f6597e34c60b14a58ef2583bcbb1d0e21b71a264fad2648ecc545031c7ed598772ffe875bf94a488389a49e6025e1b2a1f07ec598d0d9aa8ef7dd2733c8502c49d1d1323f1ae664e82e8a5e14978d52ab448ba9b1afc78f06c8cd17415a17"; @@ -13,12 +14,42 @@ pub fn good_update2() -> Vec> { vec![bytes] } -pub fn multiple_updates() -> Vec> { +pub fn multiple_updates_same_vaa() -> Vec> { let hex_str = "504e41550100000003b801000000040d02e57b0f291daa4d2f02f5c4a18793b278b238338f472d17897f8f0866549f77571cfe71fa55bae7f340b9124511559b73a0cf01c72adc8a8d9963cebecc5a503801039507a96b155046ab039f7c9cad17a4927e2ff34763bca9b65d572ddc7a5f019832ffbeeb5295447bfdb989efa0314865bb4571770ad8e75ae7a083288d6de232010412e7333ab5cf0f20274b0907da43b52016d5a095bb846962d13a222e4af1e7e63f7a8db49de04feb70f07a0e274dc58acc7a4c386a099369412c6813ba39916100063da672f75cf1d397829a39461e311ca366366828be8d12b19a00c552e7c8c5e7746b36d97dccc54e5b3aeae188b372ec885dc1fbd9c2285ce458764c86f0c1bb0008863aa237e9fe339683992121249a2e520b6483a3b3b60c703a1eb09ef33266312e729ff6d398e1a60be8474a95803cd1641ef6c1de2c74f3cd7e1f2510c919f9000a3bd5ec58424b21c48552c3be0f9cccd6e6c641eee2b4e550fb88cc93cfdf10c7409344ec3e81df711a293baba565a85e620d20028d9738e53939fa52f19ce622010b000f803511f89f02610fbece34fe327afb55196cc3e522bb28d71d6e4d5523ac77ca1afbbd8a28b4fe05c7f2aa1c3f428c89fe21096ba67bc505cbfa6ead9808010c315b34c9cac03647df4e12a050f8b739763498aa23999244036e09010e2a79a46d0cbabc22c535542896bc22df05dc5480db06a370dffeb0814424870fd50c21000d4a562686000b65df4e0ca00d2e00d10db9e913b481337ee1c80bb47b25553afb693d7be0c17f6fb106909a1eed52a6c27739471b719d4c450b99b066a02bd2c9010e309508bc7128030ca4b19fc34c0ee0e62eebb549c759c2e8ccfdf062793e41e935754ae1d5356ba98446fa2eaa837ae4b413d1ccdf1af6d9060a2885f18c19e1010f3e2ff50704a6ad1b491cb93a1e4678c0f58b91540ba3ce3b4424c96abbe922562c924debb3336ab2fe835237f16912d768e6e5b739f2ab44b57a1e2607c9bb89001070d0dfac758a38342b107870b4d5761df9e785c6be589317c4b1dad3c08998f11214c29201d172b278aa6f4d57171f0f05fb7a2718e6da6df4449e8897c0c2ac0011d9e885989fa2363ec311bf4e9ebd8738d4b3ecaf9a31c09ce06f9876c3ab772034c1df9ca09c847ee81de80a1f0f8592019fa60e55b02b657b8a7c99bee04701016866e28300000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000008812f80014155575600000000000d8ebd6500002710f015dfd43b23aad91dcd4a7a8a113ed2d39233f202005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009fee44efa2300000000e7f6ffe3fffffff8000000006866e283000000006866e283000009fb4f364d0000000000e98d2f400c2704dab60f1b310d567acb60d77a3ce8003a6f564e8e1f567f00f004381d755e160a07372977a99288dcc9c9477cf9c1bb095403b514082aa774f7b243003e30548cbd97e8191d5ef2732796e06f84f05543a171f1e66052aa515c41a2d994a0d13e2e4016e6a28823201a52d408a5024797ec4b7629406062dd9ccc30a5d1eb4ac8b4a28a3d464bf4335ceda7646e03c29cc24b6c7c5e5924e6e69400a2c90561c9a2e4555084af13fbc7eaa0a884b75d4d1197933ac174b62c4b9b1cde3dd496f5e54cd2e01cdca0ba5c5a80a2bbd0d9d5dfb7aab5b638ef883e4e55f78a1536fe79c5c3e16cda9b53e364e3bbe95f005500ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace0000003c480c0e980000000009727f59fffffff8000000006866e283000000006866e2830000003c3597da300000000007d3439a0ccf5f10d7559e184107e994663aa0fc8f81718c0b281162b77eb09c774da30e2db5674df62494b3da820f6c986a0f32d1a195b6bc4676891d4e28cdb4e2f09dd47db3243547b37bdbb9799c82a42d6f1f18f8e17d7bed68408ef26e184f21e9b640e2c9f0416d91987acbe6fa8e72c2c99fa548f83c0eb5dd3c269ef52101521ef0b3d26f50b07dae68311bd138338881b20b78f8d21d2bfc27e9ac849b4c659d61c9a2e4555084af13fbc7eaa0a884b75d4d1197933ac174b62c4b9b1cde3dd496f5e54cd2e01cdca0ba5c5a80a2bbd0d9d5dfb7aab5b638ef883e4e55f78a1536fe79c5c3e16cda9b53e364e3bbe95f"; let bytes = Vec::from_hex(hex_str).expect("Invalid hex string"); vec![bytes] } +pub fn multiple_updates_diff_vaa() -> Vec> { + let hex_str_update_1 = "504e41550100000003b801000000040d0168bad50bb1470e136368ebadeb842cf5256547a30cd65c320a0e476bca15f204326806e4290c004925040f5eea31592c55341936fe7e7537d7b4172f308fc79701033b17478509bf096ebc6107afaaf9f339f68d3ad7ebd9267585cd945b91c93f687550c07d4526dc6f2ad0335c1e849977d91d2e61be04d746a611b444af272a9f0104ce96c5a8d9e4e869c2b7ae54980bf9f315af3d93fe827a346b3b55041e019e982350498c7094c77f09567cd3f2a9961940e304666fb08bfbfac7aa1a6ec157cf010639036dea5439380e1c946f76f06480965b60edf280272ab7f649840e289e3d740e4822619e5608811c66158d22ccdea633961687b3afec2751a53a37b3fd6f4a010a370bf667e0fd0b6df27ae87e94513740d1581ca9eadc15b049b5ce4d96b57ba85f92a7bdc478fde36efd7ab80674048589421fc2644457d7b4e398bc1b5c01f0010bb5ef6559a20289cf9df4a8c076baecd3d8e3567973acf975ee52d0301b8cbddd7bb2e4348fb59020bae2caefd57945cf1107cff7f5fd068079fa59ea27e0e702000cae84bce54e40a0583d8c957ddab0388d053a85622cd83c3de49e4bc4acf515351e118f4c36b903f09fe3afd7ce5499c73c37e80d742fdfbb1a57d7f442f915f7000d90c05b57e9592b303305b0e2a88b05f5b006a5f911ac9feba74c309acbfc3af8270b4d8c0759677db601af1893ec4523f023ee6810070148cd017ca2fe2d5663010e17a7472d37425d9f1505e998736d4138f6f35c620c195340ef87ca0d155cf3aa12fe9c0a9c6341411734dacbc53e36895efa69c9895d682bc6329294a49fd928000fed2cb761a8837d87cf827141eedfeafd1901e38957930bf56cc044ebf2c34e3e06bd8197b10d356236acb2c31be6031b95caf2d7492e2744b176bf8a4a357cb70110f22c1178f5c734e83134432c2f5c76cb6462ccba9db0177640cde08b5413ce09630a9c0d5682ee2a1acca1f5d0a6a3583b9578c6e0fbb2d489e252ec7e5960a90011d984560f66ce62be4ba2512e2d62777429f37d6020f9dcb9a0ac54522f80462b4ff33ab5c832748e50cda01e34eef28271982ac22b216cac2a6bde33a83f6bfd011207131b4a1ab2f2ed984cd444210c5c4147d5da72b27d1fdbf6f1a087141ab6971b20175fd67abc937ad69a42991b780804e67e926a8ca2b218521d6572c394c100686ed88a00000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71000000000894a31a014155575600000000000da2316b00002710d957df1a464d0193bc0c9dd3b555d0544a04623e010055003fa4252848f9f0a1480be62745a4629d9eb1322aebab8a791e344b3b9c1adcf50000000002181de10000000000008db7fffffff800000000686ed88a00000000686ed88a00000000021501d40000000000008b300c29ff39535a48e8f09021a1fee7b9e887d68522dd790970609044b11d98aa7d4beb0d1e390c89ccad2fda83fd5316ad4483fc398b6534be617d42690cc27297ccbf19315c79064275612a0d16a2536fdafaca0648bd28b54a014a468906203c8a9d3deadd4ec12dd380bdd27f9a9bb41a5e841d23671743da3125f40b479518be5250080ac78df8826fb59d02dd07b310b69f954dea12b87cb5aa66af75d3da3f7327578f8ed0c0a7b98d1becad74b16e03ff52eee04497971d9985fd9cc05215490b44499df2c3a64f6fefa743421d947d34de37e185b242db065c8f89e9bb028a3710646273f0721e26c68dbd85fb20"; + let hex_str_update_2 = "504e41550100000003b801000000040d0239010392dab908eb9903d480abf8118d887f2a0c5eaeb9062e6eabab86c1b382127604c63358a7266cc5bade7726e159403c2bf317c7b3a4d8b489bfad4e334301031823d70352d3260226cbdddab0cf7d1584c0e1d23d4358ed12f9620e18a0db2154fbb096ac4cb8d5728e2cecf2b1398d7b9b51954f3fb8b4f59990ce017b0260000495e2691d8e6a0537d8ab3f41b5eb655acde7fbeaea0fdbe1f582383680f54c8a3a697c2c0f8b4110422f1b6beb0bfb601c929148b54dbf85fb19c333ccbb833c00066993a56c5980bf17d2790b933861fffb1fd09618921a90db4ab82cc8b148301f1a55d804d14cb39f648fdb0ef8c9ef1e24edc38d30f2aea7151025240a614bca0008a64a366c59bd6c4ce9d24a0e3beef2a33d28546826b1b969af184a257d648aab5672ad8a9eaf14473da40327e12e5c18168892bcebd693c8bed3df8ee50b85db010a36daa7c639c412969283f83749af93aef2464b27b83914b6026b721a59c8a04446a655686725247bd9154c71ca66505719df5867f775863a788d8bffb1bd637c000b237772560d72da81a782e89b138caf8bf1221b929ead77ca7d178b7b7af1c9141d9e77e22c98fe41b819f023695e6feed6f5215a5cdb6436bf52dc3c4c93e309010c89f2f3c64a8c77ccea47448e7871bbd70b59ed5761e5677458dbe6f82796efa2399e9ad9bf846d88d4688f1d19f9e2adeb2299017baf015c36a811d05c539b86000d6ba11d2f9a0edfd3a4bc23024d18dd010a83803faa79d40aec10a4deee40e8dd3c4c5401118b67bd6d879683cae3ea83d4f9afa744c655775615a7ce34237a02000e09a554d70c0f8e57bb79ce41552e38b836ad7b6bd1967e60c880f831341ad412699e4a9f5346713a6db2c7032bb7d1b3cc8e42f49ba17000f9d0916a13f2debf000f1ce88af88b96aaeb0104d4c966303eb9609df1b851a0d6149d05bba82f3fd70820a26d7f9d6fe18a7653fd3e3eda94fd9184726dadd2e8d58d09a8473e919f0800104583407293c41bef15c05ac20fc45fd5f9d00639c5b1f738d1ba42cd290fe5291e05219cefa8568806bfc1de76bcf5f799c90c9c6dd54bd69f9d459e994acb7a00110638c8067b42005ae678a7619e9eaad5fb66f0630547ab252179668e60b738c479ba6ff7e1f3dcffddab15e1bfebf93e0e4cb051535bdda3ecef6620aea32132016866e56400000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000008813690014155575600000000000d8ec4750000271098d4f856e398eb41afbd0f2b24ad80e58b1f57b601005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009fdcc9378c600000001105b4d5afffffff8000000006866e564000000006866e564000009fbf79e7bc000000000e99c0d1c0c02b95abadee324fbb6534576de1507c74c8ddef2b928c314cb3d4978a5ada03db907df05ba0fc051e659facec6479c324c276e5098fde9dcae0b462cd32d9e2e5b617b51ced85d38a8456022f3ab370d3c45a07acb686cfb39976b2f4bb1007a91e599951ed929f714a04dab0e6bd885a0c91a076f3b83ee8f765b70a3edda569876102f2c62cae15024e529a2e5e17c50411aa736c7511278a92f4d9cdda3239057c3a942a1365a58771734a982e41e1d7aa8bae87748f1becd045fcb5e1cb1993e978168147d6be8a2cba24a3cc8a2f78e7313f18c87ec2bb238510ebeb47aab50a449fd2ce3dc6b8c0d08d361c102"; + let bytes_1 = Vec::from_hex(hex_str_update_1).expect("Invalid hex string"); + let bytes_2 = Vec::from_hex(hex_str_update_2).expect("Invalid hex string"); + + vec![bytes_1, bytes_2] +} + +pub fn multiple_updates_diff_vaa_results() -> [(U64, I32, I64, U64, I64, U64); 2] { + [ + ( + U64::from(1752094858u64), + I32::from_le_bytes((-8i32).to_le_bytes()), + I64::from_le_bytes(35134945i64.to_le_bytes()), + U64::from(36279u64), + I64::from_le_bytes(34931156i64.to_le_bytes()), + U64::from(35632u64), + ), + ( + U64::from(1751573860u64), + I32::from_le_bytes((-8i32).to_le_bytes()), + I64::from_le_bytes(10985663592646i64.to_le_bytes()), + U64::from(4569386330u64), + I64::from_le_bytes(10977795800000i64.to_le_bytes()), + U64::from(3919318300u64), + ), + ] +} + pub fn good_update1_results() -> (U64, I32, I64, U64, I64, U64) { ( U64::from(1751563000u64), From a0310a260c0a69680e5e31b3388b4e80496ff26d Mon Sep 17 00:00:00 2001 From: Ayush Suresh Date: Wed, 9 Jul 2025 16:32:28 -0500 Subject: [PATCH 06/22] imported mock_instant crate --- target_chains/stylus/Cargo.lock | 7 +++++++ target_chains/stylus/contracts/pyth-receiver/Cargo.toml | 1 + 2 files changed, 8 insertions(+) diff --git a/target_chains/stylus/Cargo.lock b/target_chains/stylus/Cargo.lock index 5551eab31c..adde73d5a9 100644 --- a/target_chains/stylus/Cargo.lock +++ b/target_chains/stylus/Cargo.lock @@ -3286,6 +3286,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "mock_instant" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce6dd36094cac388f119d2e9dc82dc730ef91c32a6222170d630e5414b956e6" + [[package]] name = "motsu" version = "0.1.0" @@ -3982,6 +3988,7 @@ dependencies = [ "ethers", "eyre", "hex", + "mock_instant", "motsu 0.9.1", "pythnet-sdk", "serde", diff --git a/target_chains/stylus/contracts/pyth-receiver/Cargo.toml b/target_chains/stylus/contracts/pyth-receiver/Cargo.toml index f3d8a12ba8..8b4921655d 100644 --- a/target_chains/stylus/contracts/pyth-receiver/Cargo.toml +++ b/target_chains/stylus/contracts/pyth-receiver/Cargo.toml @@ -26,6 +26,7 @@ stylus-sdk = { version = "0.9.0", features = ["stylus-test"] } dotenv = "0.15.0" motsu = "0.9.0" wormhole-contract = { path = "../wormhole" } +mock_instant = "0.6.0" [features] default = ["mini-alloc"] From 0681af5f5336854ba97634c5eac1b75f23c15342 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 9 Jul 2025 21:42:54 +0000 Subject: [PATCH 07/22] feat: implement mock_instant integration for get_current_timestamp - Modified get_current_timestamp to use MockClock::time().as_secs() in test mode - Added MockClock::set_time(Duration::from_secs(1761573860)) to three specific tests: - test_get_price_no_older_than_with_random_id_reverts_with_price_unavailable - test_get_price_no_older_than_where_update_younger_than_max_age_returns_price - test_get_price_no_older_than_reverts_too_old - Contract functionality unchanged (still uses block_timestamp in production) - All specified tests pass with mocked timestamp Co-Authored-By: ayush.suresh@dourolabs.xyz --- .../stylus/contracts/pyth-receiver/src/integration_tests.rs | 5 +++++ target_chains/stylus/contracts/pyth-receiver/src/lib.rs | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs index fb52702721..ed5de43897 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs @@ -7,6 +7,8 @@ mod test { use motsu::prelude::*; use pythnet_sdk::wire::v1::{AccumulatorUpdateData, Proof}; use wormhole_contract::WormholeContract; + use mock_instant::global::MockClock; + use std::time::Duration; 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, @@ -191,6 +193,7 @@ mod test { wormhole_contract: Contract, alice: Address, ) { + MockClock::set_time(Duration::from_secs(1761573860)); pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice); let random_id: [u8; 32] = [ @@ -215,6 +218,7 @@ mod test { wormhole_contract: Contract, alice: Address, ) { + MockClock::set_time(Duration::from_secs(1761573860)); pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice); let update_data = good_update2(); @@ -240,6 +244,7 @@ mod test { wormhole_contract: Contract, alice: Address, ) { + MockClock::set_time(Duration::from_secs(1761573860)); pyth_wormhole_init(&pyth_contract, &wormhole_contract, &alice); let update_data = good_update2(); diff --git a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs index 3ec35c650d..a8973d3521 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs @@ -12,6 +12,9 @@ mod structs; #[cfg(test)] mod test_data; +#[cfg(test)] +use mock_instant::global::MockClock; + use alloc::vec::Vec; use stylus_sdk::{ alloy_primitives::{Address, FixedBytes, I32, I64, U16, U256, U32, U64}, @@ -377,7 +380,7 @@ impl PythReceiver { fn get_current_timestamp(&self) -> u64 { #[cfg(test)] { - 1761573860u64 + MockClock::time().as_secs() } #[cfg(not(test))] { From ba64927b6fa7ea77bceed629094cac59ff40694a Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 9 Jul 2025 21:44:36 +0000 Subject: [PATCH 08/22] feat: add cfg(test) attributes to all test_data.rs functions - Added #[cfg(test)] to all 9 functions in test_data.rs: - good_update1() - good_update2() - multiple_updates_same_vaa() - multiple_updates_diff_vaa() - multiple_updates_diff_vaa_results() - good_update1_results() - multiple_updates_results() - good_update2_results() - current_guardians() - Ensures test data functions are only compiled during testing - All tests continue to pass with cfg(test) attributes Co-Authored-By: ayush.suresh@dourolabs.xyz --- .../stylus/contracts/pyth-receiver/src/test_data.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs index 29d2ea8c9f..e27298a206 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs @@ -2,24 +2,28 @@ use alloy_primitives::{address, Address, I32, I64, U64}; use hex::FromHex; use std::vec; +#[cfg(test)] pub fn good_update1() -> Vec> { let hex_str = "504e41550100000003b801000000040d0216f3809b6396fdb0708bc94515ddb96a3bc8fb1993916e74f522ab4c34a268836a0bb38786303b55cc40ecb50d18c92bf9fd61688a143f3d24a73a3f468e4ab0000365be4f3a330fe96bab246922d9fa4816a865dec40d7c522e37f7e3605673b8f52eb30a4dad7aee3e1ac4b21337b8831c6147ef6e359e843b307872e83b5c7fe80004b6f12766eb395d04bdb146b1b69a4b9a8831a9c9ea20ee841d55efe72c629aef17038b925584493af7882981260b09587d73b6463415f4e1f8fb0a2a2c959c8301065c18a776cf558e43494bf31dd26ac0e3aed07a01ca0063abcfca3736b892368e4bf8b957f2d2e83ff9eb3fa8f667ef97a5f48c286103f70fda4a72e077719a0200085896c930febfb864a8c292bde679092e386e53389cb2d26bd12ceed64d22c0cd27676dc5c46d3e3c5949abbce89d4cc5ec378cfbf9ab1b0c24cfeb3371df4864000a1c67e67adea9f8a71eee76765f1fe4c7d9539d21b62d0336513692897cc6acbe1c827599a1f8c73b7478e8d788443b4cfd4e373344ab1ac9f771c9c494124863000b7e08e1cc1291340e6ec7d1b04c6a9c63f74077a074ee68edf4f95cf24c9743620f8abc8213884c8e4848fb76ec319d365e0cdc746a6e534a4cb828e51719be79010c61a2fedeedf34e4c80624d80cb93e24bafe9f6d23339173004d84e61c2395bfb5f552e87b901beb192ba6f4fc905eae30317c52b8614071e08a265592f24e8de000de38d08612edc5ebc863ea5a96325cb991750a94ff0e50f86bc322cce81db7cd17cb4ed3703f7477eb111a9d881e1345f5b79d618814f31b46034196563ee6a18000e5b11510d585a2decaba0be9e71386865b6069061478f7254d7852d55116569eb426c385267e40264d16db08e0f1a9e2c44b7d1c926d3c3ba662b212572386483010fa1ad0278402104b146b6f4d1cf85ac4df961d24eea0c7948b700f9973596cad130abfff25feef37125ba38507f34308d967455651e7014e40264a0c6510d3af001101f2e4e70868d6c327c92229537f1ffa33e488da3140ccc086f8210b437b162190742bd01ad1cb495a93f20045b4bb47e1562fdd82a8a1548d87d788a492b17190111847f5095df3edefc58be0956aee19876e850516e132506fd67504afee3c8cf240f07fb607b3c8282a2e56dcad23959e6759bdf8ad345ba8150448da56ff34fcc016866baf800000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71000000000880cea9014155575600000000000d8e5c8d0000271085e6ab1bb044f57c4cd6c1d32aa0a82a5032198301005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009f9828e420300000001284f2da6fffffff8000000006866baf8000000006866baf8000009f3b955a26000000001062cb8780c1283a49180b4986f0dec3c746d3daeb597887747b8f66a09876e1253a1ebb8a6bc4a5793daaa343db6057b82ec29715d7e1db0ffd6db523f7b80b03e3866ef5f5c80728801b92f5acecc28d8517e5615335d89c553f94b4370f3a20be0bc23e0fd401c4e5bd8bd32948a26233fc48f116428a490f087030ccfc442753e3074e2b9bbc1c61a009d86aaa200645c627a6b7f2f6597e34c60b14a58ef2583bcbb1d0e21b71a264fad2648ecc545031c7ed598772ffe875bf94a488389a49e6025e1b2a1f07ec598d0d9aa8ef7dd2733c8502c49d1d1323f1ae664e82e8a5e14978d52ab448ba9b1afc78f06c8cd17415a17"; let bytes = Vec::from_hex(hex_str).expect("Invalid hex string"); vec![bytes] } +#[cfg(test)] pub fn good_update2() -> Vec> { let hex_str = "504e41550100000003b801000000040d0239010392dab908eb9903d480abf8118d887f2a0c5eaeb9062e6eabab86c1b382127604c63358a7266cc5bade7726e159403c2bf317c7b3a4d8b489bfad4e334301031823d70352d3260226cbdddab0cf7d1584c0e1d23d4358ed12f9620e18a0db2154fbb096ac4cb8d5728e2cecf2b1398d7b9b51954f3fb8b4f59990ce017b0260000495e2691d8e6a0537d8ab3f41b5eb655acde7fbeaea0fdbe1f582383680f54c8a3a697c2c0f8b4110422f1b6beb0bfb601c929148b54dbf85fb19c333ccbb833c00066993a56c5980bf17d2790b933861fffb1fd09618921a90db4ab82cc8b148301f1a55d804d14cb39f648fdb0ef8c9ef1e24edc38d30f2aea7151025240a614bca0008a64a366c59bd6c4ce9d24a0e3beef2a33d28546826b1b969af184a257d648aab5672ad8a9eaf14473da40327e12e5c18168892bcebd693c8bed3df8ee50b85db010a36daa7c639c412969283f83749af93aef2464b27b83914b6026b721a59c8a04446a655686725247bd9154c71ca66505719df5867f775863a788d8bffb1bd637c000b237772560d72da81a782e89b138caf8bf1221b929ead77ca7d178b7b7af1c9141d9e77e22c98fe41b819f023695e6feed6f5215a5cdb6436bf52dc3c4c93e309010c89f2f3c64a8c77ccea47448e7871bbd70b59ed5761e5677458dbe6f82796efa2399e9ad9bf846d88d4688f1d19f9e2adeb2299017baf015c36a811d05c539b86000d6ba11d2f9a0edfd3a4bc23024d18dd010a83803faa79d40aec10a4deee40e8dd3c4c5401118b67bd6d879683cae3ea83d4f9afa744c655775615a7ce34237a02000e09a554d70c0f8e57bb79ce41552e38b836ad7b6bd1967e60c880f831341ad412699e4a9f5346713a6db2c7032bb7d1b3cc8e42f49ba17000f9d0916a13f2debf000f1ce88af88b96aaeb0104d4c966303eb9609df1b851a0d6149d05bba82f3fd70820a26d7f9d6fe18a7653fd3e3eda94fd9184726dadd2e8d58d09a8473e919f0800104583407293c41bef15c05ac20fc45fd5f9d00639c5b1f738d1ba42cd290fe5291e05219cefa8568806bfc1de76bcf5f799c90c9c6dd54bd69f9d459e994acb7a00110638c8067b42005ae678a7619e9eaad5fb66f0630547ab252179668e60b738c479ba6ff7e1f3dcffddab15e1bfebf93e0e4cb051535bdda3ecef6620aea32132016866e56400000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000008813690014155575600000000000d8ec4750000271098d4f856e398eb41afbd0f2b24ad80e58b1f57b601005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009fdcc9378c600000001105b4d5afffffff8000000006866e564000000006866e564000009fbf79e7bc000000000e99c0d1c0c02b95abadee324fbb6534576de1507c74c8ddef2b928c314cb3d4978a5ada03db907df05ba0fc051e659facec6479c324c276e5098fde9dcae0b462cd32d9e2e5b617b51ced85d38a8456022f3ab370d3c45a07acb686cfb39976b2f4bb1007a91e599951ed929f714a04dab0e6bd885a0c91a076f3b83ee8f765b70a3edda569876102f2c62cae15024e529a2e5e17c50411aa736c7511278a92f4d9cdda3239057c3a942a1365a58771734a982e41e1d7aa8bae87748f1becd045fcb5e1cb1993e978168147d6be8a2cba24a3cc8a2f78e7313f18c87ec2bb238510ebeb47aab50a449fd2ce3dc6b8c0d08d361c102"; let bytes = Vec::from_hex(hex_str).expect("Invalid hex string"); vec![bytes] } +#[cfg(test)] pub fn multiple_updates_same_vaa() -> Vec> { let hex_str = "504e41550100000003b801000000040d02e57b0f291daa4d2f02f5c4a18793b278b238338f472d17897f8f0866549f77571cfe71fa55bae7f340b9124511559b73a0cf01c72adc8a8d9963cebecc5a503801039507a96b155046ab039f7c9cad17a4927e2ff34763bca9b65d572ddc7a5f019832ffbeeb5295447bfdb989efa0314865bb4571770ad8e75ae7a083288d6de232010412e7333ab5cf0f20274b0907da43b52016d5a095bb846962d13a222e4af1e7e63f7a8db49de04feb70f07a0e274dc58acc7a4c386a099369412c6813ba39916100063da672f75cf1d397829a39461e311ca366366828be8d12b19a00c552e7c8c5e7746b36d97dccc54e5b3aeae188b372ec885dc1fbd9c2285ce458764c86f0c1bb0008863aa237e9fe339683992121249a2e520b6483a3b3b60c703a1eb09ef33266312e729ff6d398e1a60be8474a95803cd1641ef6c1de2c74f3cd7e1f2510c919f9000a3bd5ec58424b21c48552c3be0f9cccd6e6c641eee2b4e550fb88cc93cfdf10c7409344ec3e81df711a293baba565a85e620d20028d9738e53939fa52f19ce622010b000f803511f89f02610fbece34fe327afb55196cc3e522bb28d71d6e4d5523ac77ca1afbbd8a28b4fe05c7f2aa1c3f428c89fe21096ba67bc505cbfa6ead9808010c315b34c9cac03647df4e12a050f8b739763498aa23999244036e09010e2a79a46d0cbabc22c535542896bc22df05dc5480db06a370dffeb0814424870fd50c21000d4a562686000b65df4e0ca00d2e00d10db9e913b481337ee1c80bb47b25553afb693d7be0c17f6fb106909a1eed52a6c27739471b719d4c450b99b066a02bd2c9010e309508bc7128030ca4b19fc34c0ee0e62eebb549c759c2e8ccfdf062793e41e935754ae1d5356ba98446fa2eaa837ae4b413d1ccdf1af6d9060a2885f18c19e1010f3e2ff50704a6ad1b491cb93a1e4678c0f58b91540ba3ce3b4424c96abbe922562c924debb3336ab2fe835237f16912d768e6e5b739f2ab44b57a1e2607c9bb89001070d0dfac758a38342b107870b4d5761df9e785c6be589317c4b1dad3c08998f11214c29201d172b278aa6f4d57171f0f05fb7a2718e6da6df4449e8897c0c2ac0011d9e885989fa2363ec311bf4e9ebd8738d4b3ecaf9a31c09ce06f9876c3ab772034c1df9ca09c847ee81de80a1f0f8592019fa60e55b02b657b8a7c99bee04701016866e28300000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000008812f80014155575600000000000d8ebd6500002710f015dfd43b23aad91dcd4a7a8a113ed2d39233f202005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009fee44efa2300000000e7f6ffe3fffffff8000000006866e283000000006866e283000009fb4f364d0000000000e98d2f400c2704dab60f1b310d567acb60d77a3ce8003a6f564e8e1f567f00f004381d755e160a07372977a99288dcc9c9477cf9c1bb095403b514082aa774f7b243003e30548cbd97e8191d5ef2732796e06f84f05543a171f1e66052aa515c41a2d994a0d13e2e4016e6a28823201a52d408a5024797ec4b7629406062dd9ccc30a5d1eb4ac8b4a28a3d464bf4335ceda7646e03c29cc24b6c7c5e5924e6e69400a2c90561c9a2e4555084af13fbc7eaa0a884b75d4d1197933ac174b62c4b9b1cde3dd496f5e54cd2e01cdca0ba5c5a80a2bbd0d9d5dfb7aab5b638ef883e4e55f78a1536fe79c5c3e16cda9b53e364e3bbe95f005500ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace0000003c480c0e980000000009727f59fffffff8000000006866e283000000006866e2830000003c3597da300000000007d3439a0ccf5f10d7559e184107e994663aa0fc8f81718c0b281162b77eb09c774da30e2db5674df62494b3da820f6c986a0f32d1a195b6bc4676891d4e28cdb4e2f09dd47db3243547b37bdbb9799c82a42d6f1f18f8e17d7bed68408ef26e184f21e9b640e2c9f0416d91987acbe6fa8e72c2c99fa548f83c0eb5dd3c269ef52101521ef0b3d26f50b07dae68311bd138338881b20b78f8d21d2bfc27e9ac849b4c659d61c9a2e4555084af13fbc7eaa0a884b75d4d1197933ac174b62c4b9b1cde3dd496f5e54cd2e01cdca0ba5c5a80a2bbd0d9d5dfb7aab5b638ef883e4e55f78a1536fe79c5c3e16cda9b53e364e3bbe95f"; let bytes = Vec::from_hex(hex_str).expect("Invalid hex string"); vec![bytes] } +#[cfg(test)] pub fn multiple_updates_diff_vaa() -> Vec> { let hex_str_update_1 = "504e41550100000003b801000000040d0168bad50bb1470e136368ebadeb842cf5256547a30cd65c320a0e476bca15f204326806e4290c004925040f5eea31592c55341936fe7e7537d7b4172f308fc79701033b17478509bf096ebc6107afaaf9f339f68d3ad7ebd9267585cd945b91c93f687550c07d4526dc6f2ad0335c1e849977d91d2e61be04d746a611b444af272a9f0104ce96c5a8d9e4e869c2b7ae54980bf9f315af3d93fe827a346b3b55041e019e982350498c7094c77f09567cd3f2a9961940e304666fb08bfbfac7aa1a6ec157cf010639036dea5439380e1c946f76f06480965b60edf280272ab7f649840e289e3d740e4822619e5608811c66158d22ccdea633961687b3afec2751a53a37b3fd6f4a010a370bf667e0fd0b6df27ae87e94513740d1581ca9eadc15b049b5ce4d96b57ba85f92a7bdc478fde36efd7ab80674048589421fc2644457d7b4e398bc1b5c01f0010bb5ef6559a20289cf9df4a8c076baecd3d8e3567973acf975ee52d0301b8cbddd7bb2e4348fb59020bae2caefd57945cf1107cff7f5fd068079fa59ea27e0e702000cae84bce54e40a0583d8c957ddab0388d053a85622cd83c3de49e4bc4acf515351e118f4c36b903f09fe3afd7ce5499c73c37e80d742fdfbb1a57d7f442f915f7000d90c05b57e9592b303305b0e2a88b05f5b006a5f911ac9feba74c309acbfc3af8270b4d8c0759677db601af1893ec4523f023ee6810070148cd017ca2fe2d5663010e17a7472d37425d9f1505e998736d4138f6f35c620c195340ef87ca0d155cf3aa12fe9c0a9c6341411734dacbc53e36895efa69c9895d682bc6329294a49fd928000fed2cb761a8837d87cf827141eedfeafd1901e38957930bf56cc044ebf2c34e3e06bd8197b10d356236acb2c31be6031b95caf2d7492e2744b176bf8a4a357cb70110f22c1178f5c734e83134432c2f5c76cb6462ccba9db0177640cde08b5413ce09630a9c0d5682ee2a1acca1f5d0a6a3583b9578c6e0fbb2d489e252ec7e5960a90011d984560f66ce62be4ba2512e2d62777429f37d6020f9dcb9a0ac54522f80462b4ff33ab5c832748e50cda01e34eef28271982ac22b216cac2a6bde33a83f6bfd011207131b4a1ab2f2ed984cd444210c5c4147d5da72b27d1fdbf6f1a087141ab6971b20175fd67abc937ad69a42991b780804e67e926a8ca2b218521d6572c394c100686ed88a00000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71000000000894a31a014155575600000000000da2316b00002710d957df1a464d0193bc0c9dd3b555d0544a04623e010055003fa4252848f9f0a1480be62745a4629d9eb1322aebab8a791e344b3b9c1adcf50000000002181de10000000000008db7fffffff800000000686ed88a00000000686ed88a00000000021501d40000000000008b300c29ff39535a48e8f09021a1fee7b9e887d68522dd790970609044b11d98aa7d4beb0d1e390c89ccad2fda83fd5316ad4483fc398b6534be617d42690cc27297ccbf19315c79064275612a0d16a2536fdafaca0648bd28b54a014a468906203c8a9d3deadd4ec12dd380bdd27f9a9bb41a5e841d23671743da3125f40b479518be5250080ac78df8826fb59d02dd07b310b69f954dea12b87cb5aa66af75d3da3f7327578f8ed0c0a7b98d1becad74b16e03ff52eee04497971d9985fd9cc05215490b44499df2c3a64f6fefa743421d947d34de37e185b242db065c8f89e9bb028a3710646273f0721e26c68dbd85fb20"; let hex_str_update_2 = "504e41550100000003b801000000040d0239010392dab908eb9903d480abf8118d887f2a0c5eaeb9062e6eabab86c1b382127604c63358a7266cc5bade7726e159403c2bf317c7b3a4d8b489bfad4e334301031823d70352d3260226cbdddab0cf7d1584c0e1d23d4358ed12f9620e18a0db2154fbb096ac4cb8d5728e2cecf2b1398d7b9b51954f3fb8b4f59990ce017b0260000495e2691d8e6a0537d8ab3f41b5eb655acde7fbeaea0fdbe1f582383680f54c8a3a697c2c0f8b4110422f1b6beb0bfb601c929148b54dbf85fb19c333ccbb833c00066993a56c5980bf17d2790b933861fffb1fd09618921a90db4ab82cc8b148301f1a55d804d14cb39f648fdb0ef8c9ef1e24edc38d30f2aea7151025240a614bca0008a64a366c59bd6c4ce9d24a0e3beef2a33d28546826b1b969af184a257d648aab5672ad8a9eaf14473da40327e12e5c18168892bcebd693c8bed3df8ee50b85db010a36daa7c639c412969283f83749af93aef2464b27b83914b6026b721a59c8a04446a655686725247bd9154c71ca66505719df5867f775863a788d8bffb1bd637c000b237772560d72da81a782e89b138caf8bf1221b929ead77ca7d178b7b7af1c9141d9e77e22c98fe41b819f023695e6feed6f5215a5cdb6436bf52dc3c4c93e309010c89f2f3c64a8c77ccea47448e7871bbd70b59ed5761e5677458dbe6f82796efa2399e9ad9bf846d88d4688f1d19f9e2adeb2299017baf015c36a811d05c539b86000d6ba11d2f9a0edfd3a4bc23024d18dd010a83803faa79d40aec10a4deee40e8dd3c4c5401118b67bd6d879683cae3ea83d4f9afa744c655775615a7ce34237a02000e09a554d70c0f8e57bb79ce41552e38b836ad7b6bd1967e60c880f831341ad412699e4a9f5346713a6db2c7032bb7d1b3cc8e42f49ba17000f9d0916a13f2debf000f1ce88af88b96aaeb0104d4c966303eb9609df1b851a0d6149d05bba82f3fd70820a26d7f9d6fe18a7653fd3e3eda94fd9184726dadd2e8d58d09a8473e919f0800104583407293c41bef15c05ac20fc45fd5f9d00639c5b1f738d1ba42cd290fe5291e05219cefa8568806bfc1de76bcf5f799c90c9c6dd54bd69f9d459e994acb7a00110638c8067b42005ae678a7619e9eaad5fb66f0630547ab252179668e60b738c479ba6ff7e1f3dcffddab15e1bfebf93e0e4cb051535bdda3ecef6620aea32132016866e56400000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000008813690014155575600000000000d8ec4750000271098d4f856e398eb41afbd0f2b24ad80e58b1f57b601005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009fdcc9378c600000001105b4d5afffffff8000000006866e564000000006866e564000009fbf79e7bc000000000e99c0d1c0c02b95abadee324fbb6534576de1507c74c8ddef2b928c314cb3d4978a5ada03db907df05ba0fc051e659facec6479c324c276e5098fde9dcae0b462cd32d9e2e5b617b51ced85d38a8456022f3ab370d3c45a07acb686cfb39976b2f4bb1007a91e599951ed929f714a04dab0e6bd885a0c91a076f3b83ee8f765b70a3edda569876102f2c62cae15024e529a2e5e17c50411aa736c7511278a92f4d9cdda3239057c3a942a1365a58771734a982e41e1d7aa8bae87748f1becd045fcb5e1cb1993e978168147d6be8a2cba24a3cc8a2f78e7313f18c87ec2bb238510ebeb47aab50a449fd2ce3dc6b8c0d08d361c102"; @@ -29,6 +33,7 @@ pub fn multiple_updates_diff_vaa() -> Vec> { vec![bytes_1, bytes_2] } +#[cfg(test)] pub fn multiple_updates_diff_vaa_results() -> [(U64, I32, I64, U64, I64, U64); 2] { [ ( @@ -50,6 +55,7 @@ pub fn multiple_updates_diff_vaa_results() -> [(U64, I32, I64, U64, I64, U64); 2 ] } +#[cfg(test)] pub fn good_update1_results() -> (U64, I32, I64, U64, I64, U64) { ( U64::from(1751563000u64), @@ -61,6 +67,7 @@ pub fn good_update1_results() -> (U64, I32, I64, U64, I64, U64) { ) } +#[cfg(test)] pub fn multiple_updates_results() -> [(U64, I32, I64, U64, I64, U64); 2] { [ ( @@ -82,6 +89,7 @@ pub fn multiple_updates_results() -> [(U64, I32, I64, U64, I64, U64); 2] { ] } +#[cfg(test)] pub fn good_update2_results() -> (U64, I32, I64, U64, I64, U64) { ( U64::from(1751573860u64), @@ -93,6 +101,7 @@ pub fn good_update2_results() -> (U64, I32, I64, U64, I64, U64) { ) } +#[cfg(test)] pub fn current_guardians() -> Vec
{ vec![ address!("0x5893B5A76c3f739645648885bDCcC06cd70a3Cd3"), // Rockaway From 9e144fff4eea43ea29ce1d167c51470aff61c719 Mon Sep 17 00:00:00 2001 From: Ayush Suresh Date: Wed, 9 Jul 2025 17:26:20 -0500 Subject: [PATCH 09/22] implemented parse_price_feed_updates_unique --- .../contracts/pyth-receiver/src/error.rs | 2 + .../stylus/contracts/pyth-receiver/src/lib.rs | 50 +++++++++++++++---- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/error.rs b/target_chains/stylus/contracts/pyth-receiver/src/error.rs index 5f0bb2ecf6..4b68178d80 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/error.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/error.rs @@ -18,6 +18,7 @@ pub enum PythReceiverError { InvalidEmitterAddress, TooManyUpdates, PriceFeedNotFoundWithinRange, + NoFreshUpdate, } impl core::fmt::Debug for PythReceiverError { @@ -45,6 +46,7 @@ impl From for Vec { PythReceiverError::InvalidEmitterAddress => 14, PythReceiverError::TooManyUpdates => 15, PythReceiverError::PriceFeedNotFoundWithinRange => 16, + PythReceiverError::NoFreshUpdate => 17, }] } } diff --git a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs index 32a8f7e859..cb75a513aa 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs @@ -193,11 +193,30 @@ impl PythReceiver { pub fn update_price_feeds_if_necessary( &mut self, - _update_data: Vec>, - _price_ids: Vec<[u8; 32]>, - _publish_times: Vec, - ) { - // dummy implementation + update_data: Vec>, + price_ids: Vec<[u8; 32]>, + publish_times: Vec, + ) -> Result<(), PythReceiverError> { + if (price_ids.len() != publish_times.len()) + || (price_ids.is_empty() && publish_times.is_empty()) + { + return Err(PythReceiverError::InvalidUpdateData); + } + + for i in 0..price_ids.len() { + if (self.latest_price_info_publish_time(price_ids[i]) < publish_times[i]) { + self.update_price_feeds(update_data.clone())?; + return Ok(()); + } + } + + return Err(PythReceiverError::NoFreshUpdate); + } + + fn latest_price_info_publish_time(&self, price_id: [u8; 32]) -> u64 { + let price_id_fb: FixedBytes<32> = FixedBytes::from(price_id); + let recent_price_info = self.latest_price_info.get(price_id_fb); + recent_price_info.publish_time.get().to::() } fn update_price_feeds_internal( @@ -449,12 +468,21 @@ impl PythReceiver { pub fn parse_price_feed_updates_unique( &mut self, - _update_data: Vec>, - _price_ids: Vec<[u8; 32]>, - _min_publish_time: u64, - _max_publish_time: u64, - ) -> Vec { - Vec::new() + update_data: Vec>, + price_ids: Vec<[u8; 32]>, + min_publish_time: u64, + max_publish_time: u64, + ) -> Result, PythReceiverError> { + let price_feeds = self.parse_price_feed_updates_with_config( + update_data, + price_ids, + min_publish_time, + max_publish_time, + true, + false, + false, + ); + price_feeds } fn is_no_older_than(&self, publish_time: U64, max_age: u64) -> bool { From 6897096914b9edc37529c01e8228d19dad9a3c44 Mon Sep 17 00:00:00 2001 From: Ayush Suresh Date: Wed, 9 Jul 2025 17:52:18 -0500 Subject: [PATCH 10/22] pushing work for now --- .../stylus/contracts/pyth-receiver/src/lib.rs | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs index cb75a513aa..7bc41e7e96 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs @@ -300,7 +300,7 @@ impl PythReceiver { pub fn parse_price_feed_updates_with_config( &mut self, - update_data: Vec, + update_data: Vec>, price_ids: Vec<[u8; 32]>, min_allowed_publish_time: u64, max_allowed_publish_time: u64, @@ -308,22 +308,24 @@ impl PythReceiver { check_update_data_is_minimal: bool, store_updates_if_fresh: bool, ) -> Result, PythReceiverError> { - let price_pairs; - if store_updates_if_fresh { - price_pairs = self.update_price_feeds_internal( - update_data, - price_ids.clone(), - min_allowed_publish_time, - max_allowed_publish_time, - check_uniqueness, - )?; - } else { - price_pairs = self.parse_price_feed_updates_internal( - update_data, - min_allowed_publish_time, - max_allowed_publish_time, - check_uniqueness, - )?; + let all_parsed_price_pairs = Vec::new(); + for data in &update_data { + if store_updates_if_fresh { + all_parsed_price_pairs.extend(self.update_price_feeds_internal( + data, + price_ids.clone(), + min_allowed_publish_time, + max_allowed_publish_time, + check_uniqueness, + )?); + } else { + all_parsed_price_pairs.extend(self.parse_price_feed_updates_internal( + data, + min_allowed_publish_time, + max_allowed_publish_time, + check_uniqueness, + )?); + } } if check_update_data_is_minimal && price_ids.len() != price_pairs.len() { From 2c77720df3a611955c46efaac9f14aa5cd99b8a2 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 9 Jul 2025 22:59:07 +0000 Subject: [PATCH 11/22] fix: modify parse_price_feed_updates_with_config to preserve existing price values - Fixed compilation errors by making all_parsed_price_pairs mutable - Modified logic after first for loop to iterate through price pairs and preserve existing values - Updated parse_price_feed_updates to wrap single update_data in vector - All tests passing Co-Authored-By: ayush.suresh@dourolabs.xyz --- .../stylus/contracts/pyth-receiver/src/lib.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs index 7bc41e7e96..85297d66d8 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs @@ -287,7 +287,7 @@ impl PythReceiver { max_publish_time: u64, ) -> Result, PythReceiverError> { let price_feeds = self.parse_price_feed_updates_with_config( - update_data, + vec![update_data], price_ids, min_publish_time, max_publish_time, @@ -308,11 +308,11 @@ impl PythReceiver { check_update_data_is_minimal: bool, store_updates_if_fresh: bool, ) -> Result, PythReceiverError> { - let all_parsed_price_pairs = Vec::new(); + let mut all_parsed_price_pairs = Vec::new(); for data in &update_data { if store_updates_if_fresh { all_parsed_price_pairs.extend(self.update_price_feeds_internal( - data, + data.clone(), price_ids.clone(), min_allowed_publish_time, max_allowed_publish_time, @@ -320,7 +320,7 @@ impl PythReceiver { )?); } else { all_parsed_price_pairs.extend(self.parse_price_feed_updates_internal( - data, + data.clone(), min_allowed_publish_time, max_allowed_publish_time, check_uniqueness, @@ -328,13 +328,18 @@ impl PythReceiver { } } - if check_update_data_is_minimal && price_ids.len() != price_pairs.len() { + if check_update_data_is_minimal && all_parsed_price_pairs.len() != price_ids.len() { return Err(PythReceiverError::InvalidUpdateData); } - let price_map: BTreeMap<[u8; 32], PriceInfoReturn> = price_pairs.into_iter().collect(); - let mut result: Vec = 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); + } + } for price_id in price_ids { if let Some(price_info) = price_map.get(&price_id) { From 9f3d8093da358c3d9d29b5b3d1607e8b9fb1289b Mon Sep 17 00:00:00 2001 From: Ayush Suresh Date: Thu, 10 Jul 2025 13:18:18 -0500 Subject: [PATCH 12/22] set up integration tests --- .../pyth-receiver/src/integration_tests.rs | 16 ++++-- .../stylus/contracts/pyth-receiver/src/lib.rs | 30 +++++------ .../contracts/pyth-receiver/src/structs.rs | 8 +-- .../contracts/pyth-receiver/src/test_data.rs | 51 ++++++++++++------- 4 files changed, 63 insertions(+), 42 deletions(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs index 1caa08c58f..a5e747c262 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs @@ -114,7 +114,9 @@ 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(good_update1_feed_id()); assert!(price_result.is_ok()); assert_eq!(price_result.unwrap(), good_update1_results()); } @@ -166,7 +168,9 @@ 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(good_update1_feed_id()); assert!(price_result.is_ok()); assert_eq!(price_result.unwrap(), good_update2_results()); } @@ -179,7 +183,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(good_update1_feed_id()); assert!(price_result.is_err()); assert_eq!( price_result.unwrap_err(), @@ -233,7 +239,7 @@ mod test { let price_result = pyth_contract .sender(alice) - .get_price_no_older_than(TEST_PRICE_ID, u64::MAX); + .get_price_no_older_than(good_update1_feed_id(), u64::MAX); assert!(price_result.is_ok()); assert_eq!(price_result.unwrap(), good_update2_results()); } @@ -259,7 +265,7 @@ mod test { let price_result = pyth_contract .sender(alice) - .get_price_no_older_than(TEST_PRICE_ID, 1); + .get_price_no_older_than(good_update1_feed_id(), 1); assert!(price_result.is_err()); assert_eq!( price_result.unwrap_err(), diff --git a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs index 85297d66d8..cc404cf8c5 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs @@ -39,7 +39,7 @@ use pythnet_sdk::{ }, }, }; -use structs::{DataSource, DataSourceStorage, PriceInfoReturn, PriceInfoStorage}; +use structs::{DataSource, DataSourceStorage, PriceFeedReturn, PriceInfoStorage}; use wormhole_vaas::{Readable, Vaa, Writeable}; sol_interface! { @@ -111,7 +111,7 @@ impl PythReceiver { } } - pub fn get_price_unsafe(&self, id: [u8; 32]) -> Result { + pub fn get_price_unsafe(&self, id: [u8; 32]) -> Result { let id_fb = FixedBytes::<32>::from(id); let price_info = self.latest_price_info.get(id_fb); @@ -134,7 +134,7 @@ impl PythReceiver { &self, id: [u8; 32], age: u64, - ) -> Result { + ) -> Result { let price_info = self.get_price_unsafe(id)?; if !self.is_no_older_than(price_info.0, age) { return Err(PythReceiverError::NewPriceUnavailable); @@ -142,7 +142,7 @@ impl PythReceiver { Ok(price_info) } - pub fn get_ema_price_unsafe(&self, id: [u8; 32]) -> Result { + pub fn get_ema_price_unsafe(&self, id: [u8; 32]) -> Result { let id_fb = FixedBytes::<32>::from(id); let price_info = self.latest_price_info.get(id_fb); @@ -164,7 +164,7 @@ impl PythReceiver { &self, id: [u8; 32], age: u64, - ) -> Result { + ) -> Result { let price_info = self.get_ema_price_unsafe(id)?; if !self.is_no_older_than(price_info.0, age) { return Err(PythReceiverError::NewPriceUnavailable); @@ -204,7 +204,7 @@ impl PythReceiver { } for i in 0..price_ids.len() { - if (self.latest_price_info_publish_time(price_ids[i]) < publish_times[i]) { + if self.latest_price_info_publish_time(price_ids[i]) < publish_times[i] { self.update_price_feeds(update_data.clone())?; return Ok(()); } @@ -226,7 +226,7 @@ impl PythReceiver { min_publish_time: u64, max_publish_time: u64, _unique: bool, - ) -> Result, PythReceiverError> { + ) -> Result, PythReceiverError> { let price_pairs = self.parse_price_feed_updates_internal( update_data, min_publish_time, @@ -285,7 +285,7 @@ impl PythReceiver { price_ids: Vec<[u8; 32]>, min_publish_time: u64, max_publish_time: u64, - ) -> Result, PythReceiverError> { + ) -> Result, PythReceiverError> { let price_feeds = self.parse_price_feed_updates_with_config( vec![update_data], price_ids, @@ -307,7 +307,7 @@ impl PythReceiver { check_uniqueness: bool, check_update_data_is_minimal: bool, store_updates_if_fresh: bool, - ) -> Result, PythReceiverError> { + ) -> Result, PythReceiverError> { let mut all_parsed_price_pairs = Vec::new(); for data in &update_data { if store_updates_if_fresh { @@ -332,8 +332,8 @@ impl PythReceiver { return Err(PythReceiverError::InvalidUpdateData); } - let mut result: Vec = Vec::with_capacity(price_ids.len()); - let mut price_map: BTreeMap<[u8; 32], PriceInfoReturn> = BTreeMap::new(); + let mut result: Vec = Vec::with_capacity(price_ids.len()); + let mut price_map: BTreeMap<[u8; 32], PriceFeedReturn> = BTreeMap::new(); for (price_id, price_info) in all_parsed_price_pairs { if !price_map.contains_key(&price_id) { @@ -358,7 +358,7 @@ impl PythReceiver { min_allowed_publish_time: u64, max_allowed_publish_time: u64, check_uniqueness: bool, - ) -> Result, PythReceiverError> { + ) -> Result, 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 { @@ -375,7 +375,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: BTreeMap<[u8; 32], PriceFeedReturn> = BTreeMap::new(); match accumulator_update.proof { Proof::WormholeMerkle { vaa, updates } => { @@ -469,7 +469,7 @@ impl PythReceiver { &mut self, _update_data: Vec>, _price_ids: Vec<[u8; 32]>, - ) -> Vec { + ) -> Vec { Vec::new() } @@ -479,7 +479,7 @@ impl PythReceiver { price_ids: Vec<[u8; 32]>, min_publish_time: u64, max_publish_time: u64, - ) -> Result, PythReceiverError> { + ) -> Result, PythReceiverError> { let price_feeds = self.parse_price_feed_updates_with_config( update_data, price_ids, diff --git a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs b/target_chains/stylus/contracts/pyth-receiver/src/structs.rs index 13e419ca15..3f804725db 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/structs.rs @@ -46,9 +46,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 +57,9 @@ pub struct PriceInfoStorage { // pub ema_conf: U64, // } -pub type PriceInfoReturn = (U64, I32, I64, U64, I64, U64); +pub type PriceFeedReturn = (U64, I32, I64, U64, I64, U64); + +pub type PriceReturn = ([u8; 32], U64, I32, I64, U64, I64, U64); #[cfg(test)] mod tests { diff --git a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs index e27298a206..c241bc8da4 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs @@ -4,18 +4,31 @@ use std::vec; #[cfg(test)] pub fn good_update1() -> Vec> { - let hex_str = "504e41550100000003b801000000040d0216f3809b6396fdb0708bc94515ddb96a3bc8fb1993916e74f522ab4c34a268836a0bb38786303b55cc40ecb50d18c92bf9fd61688a143f3d24a73a3f468e4ab0000365be4f3a330fe96bab246922d9fa4816a865dec40d7c522e37f7e3605673b8f52eb30a4dad7aee3e1ac4b21337b8831c6147ef6e359e843b307872e83b5c7fe80004b6f12766eb395d04bdb146b1b69a4b9a8831a9c9ea20ee841d55efe72c629aef17038b925584493af7882981260b09587d73b6463415f4e1f8fb0a2a2c959c8301065c18a776cf558e43494bf31dd26ac0e3aed07a01ca0063abcfca3736b892368e4bf8b957f2d2e83ff9eb3fa8f667ef97a5f48c286103f70fda4a72e077719a0200085896c930febfb864a8c292bde679092e386e53389cb2d26bd12ceed64d22c0cd27676dc5c46d3e3c5949abbce89d4cc5ec378cfbf9ab1b0c24cfeb3371df4864000a1c67e67adea9f8a71eee76765f1fe4c7d9539d21b62d0336513692897cc6acbe1c827599a1f8c73b7478e8d788443b4cfd4e373344ab1ac9f771c9c494124863000b7e08e1cc1291340e6ec7d1b04c6a9c63f74077a074ee68edf4f95cf24c9743620f8abc8213884c8e4848fb76ec319d365e0cdc746a6e534a4cb828e51719be79010c61a2fedeedf34e4c80624d80cb93e24bafe9f6d23339173004d84e61c2395bfb5f552e87b901beb192ba6f4fc905eae30317c52b8614071e08a265592f24e8de000de38d08612edc5ebc863ea5a96325cb991750a94ff0e50f86bc322cce81db7cd17cb4ed3703f7477eb111a9d881e1345f5b79d618814f31b46034196563ee6a18000e5b11510d585a2decaba0be9e71386865b6069061478f7254d7852d55116569eb426c385267e40264d16db08e0f1a9e2c44b7d1c926d3c3ba662b212572386483010fa1ad0278402104b146b6f4d1cf85ac4df961d24eea0c7948b700f9973596cad130abfff25feef37125ba38507f34308d967455651e7014e40264a0c6510d3af001101f2e4e70868d6c327c92229537f1ffa33e488da3140ccc086f8210b437b162190742bd01ad1cb495a93f20045b4bb47e1562fdd82a8a1548d87d788a492b17190111847f5095df3edefc58be0956aee19876e850516e132506fd67504afee3c8cf240f07fb607b3c8282a2e56dcad23959e6759bdf8ad345ba8150448da56ff34fcc016866baf800000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71000000000880cea9014155575600000000000d8e5c8d0000271085e6ab1bb044f57c4cd6c1d32aa0a82a5032198301005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009f9828e420300000001284f2da6fffffff8000000006866baf8000000006866baf8000009f3b955a26000000001062cb8780c1283a49180b4986f0dec3c746d3daeb597887747b8f66a09876e1253a1ebb8a6bc4a5793daaa343db6057b82ec29715d7e1db0ffd6db523f7b80b03e3866ef5f5c80728801b92f5acecc28d8517e5615335d89c553f94b4370f3a20be0bc23e0fd401c4e5bd8bd32948a26233fc48f116428a490f087030ccfc442753e3074e2b9bbc1c61a009d86aaa200645c627a6b7f2f6597e34c60b14a58ef2583bcbb1d0e21b71a264fad2648ecc545031c7ed598772ffe875bf94a488389a49e6025e1b2a1f07ec598d0d9aa8ef7dd2733c8502c49d1d1323f1ae664e82e8a5e14978d52ab448ba9b1afc78f06c8cd17415a17"; + // 0xa6320c8329924601f4d092dd3f562376f657fa0b5d0cba9e4385a24aaf135384 + let hex_str = "504e41550100000003b801000000040d02cfb65be46a822da31643f7bcce6c632943a0c9bab25872525c640ec1d803832936e560a4d6344c1e98f8fe2714281f882b25bc3e1f5fd3db51a9eae49afe2fb401030f87f6065777bffb27594235323e6680ec24b953ec71f0e0e3708ff28986613b2351aba32024ea226585f90c0a2680ee40786a1978b99596af6c281a947b87bc010492608d288aeaa7393d625111da17271178e739392ac87334b01388897612e63176754d044740d80f8f5511cb92c9925592ca223f8eeea70153ccac10f4f2faee0106944014d7f07eb277fe6cd5b4adf65ec547971ab43cb56a507cb974a059cf5b623e838cb899b2401efdac1d352aabab8d4c737519611f4ae22be6addfb254002c0108e9a6f762c22e639302495af910bf305269f38460360ef32cc4e5b1369d599bd33343d56a8e9b392a8cabfd9fc31bbfa32c03433d14f7b7ecdb1975e9759f3e51010ab4322508f35ca75320715c91ed4bf1b07e89730452e3c25b78469646ea61cdc27e52030b2baed4c91b24c3fa13816d95f70095d6c6cc2e110aaf92bab7e816f7010b48e2366bfbccd42b6b790d618bbe3bae90507be6ffda461a7a42ae19f674e16d359c5743540557f401ba7d33f401d5489d0933c3c6253528d1f9c7df3c51dc11010dcc82f54596cd7fc8dac985d4d1bbe410c82f1846891077783ea8da7522725f4621b51d2c09c008826e70f5b52098669d9a872de47d8544867dc381be6e10af04000eb240c11adf380871403a158fc5ce4482629ae1ca2e8b3ab6e7cf02e20435400d065a6399a49ede59db3ad05e56d5f4d4cfcc2419ce2b21dfd2c6dc955539c66d010f93cf0f4e8db5c1467b72c4d188c3c84faeab9dcb5936c2a4a8e80c8bebe8cbc75bd757243af5f109824e5afb1cafd6995c587cc0714fff8c92b1c109a7f4644d0110a89b1ccda9b5e70e823c259ef21b09ef5dcb3e0599033abdf179292f7395e62f3aead157a15d95377dfec08656f6b3f71e68e7ea8da185c38c6f84e50beb79a8001129768f9183799b4bad3b96953ea53b7ee269cd6763b56051b0fcd93e9f6b62325a811abc9d8d401c3971b864a4a9e1910f3ad6980fccd078b36399df46bd291c00121e92dc37fb15d26237137088d139d6decbb1e1d08a7e2a2acf92eaef9cbd7a93738c702ca0faa0b7764b5a28b4ffe41febeb9c2d62706844e69831b58902d88000686fff8a00000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000008976df2014155575600000000000da4fc6f000027106529465b0781218c3d940e5d11cebff0bc1ef15401005500a6320c8329924601f4d092dd3f562376f657fa0b5d0cba9e4385a24aaf1353840000000000635f4b0000000000005117fffffff800000000686fff8a00000000686fff8a00000000006202080000000000003a710c1957911bdae55923e5b2b971a731b10567748efab84bef5a2e1ac6fbfadd24896a2d225c77a260f03b06cb7c34c3ed018d02ac3fc7eefa997ffc91dc3b50508fb4b11c6c7768bc93dd3abeaf5d912ff895be0136780546fbb2f8b42855afa013d38675d811ab3118f0b0eea13dfd64ceb16649747908f859be12f8116922a05ad919df2bca555e5177ec70ab85278ad68b057e6fdbfe50bc38c3796c43199310760180b3253701d4293f32dc1e9be7f10dc3bf2bbf60ffe85b4e0b9ba3cf87af3c472f5d0372cdec973f4ddee17e89255df7d55bea696c64c7af6e8efd51ec79d1870f4d19bc4d5c65f24bdccd341a7d"; let bytes = Vec::from_hex(hex_str).expect("Invalid hex string"); vec![bytes] } #[cfg(test)] pub fn good_update2() -> Vec> { - let hex_str = "504e41550100000003b801000000040d0239010392dab908eb9903d480abf8118d887f2a0c5eaeb9062e6eabab86c1b382127604c63358a7266cc5bade7726e159403c2bf317c7b3a4d8b489bfad4e334301031823d70352d3260226cbdddab0cf7d1584c0e1d23d4358ed12f9620e18a0db2154fbb096ac4cb8d5728e2cecf2b1398d7b9b51954f3fb8b4f59990ce017b0260000495e2691d8e6a0537d8ab3f41b5eb655acde7fbeaea0fdbe1f582383680f54c8a3a697c2c0f8b4110422f1b6beb0bfb601c929148b54dbf85fb19c333ccbb833c00066993a56c5980bf17d2790b933861fffb1fd09618921a90db4ab82cc8b148301f1a55d804d14cb39f648fdb0ef8c9ef1e24edc38d30f2aea7151025240a614bca0008a64a366c59bd6c4ce9d24a0e3beef2a33d28546826b1b969af184a257d648aab5672ad8a9eaf14473da40327e12e5c18168892bcebd693c8bed3df8ee50b85db010a36daa7c639c412969283f83749af93aef2464b27b83914b6026b721a59c8a04446a655686725247bd9154c71ca66505719df5867f775863a788d8bffb1bd637c000b237772560d72da81a782e89b138caf8bf1221b929ead77ca7d178b7b7af1c9141d9e77e22c98fe41b819f023695e6feed6f5215a5cdb6436bf52dc3c4c93e309010c89f2f3c64a8c77ccea47448e7871bbd70b59ed5761e5677458dbe6f82796efa2399e9ad9bf846d88d4688f1d19f9e2adeb2299017baf015c36a811d05c539b86000d6ba11d2f9a0edfd3a4bc23024d18dd010a83803faa79d40aec10a4deee40e8dd3c4c5401118b67bd6d879683cae3ea83d4f9afa744c655775615a7ce34237a02000e09a554d70c0f8e57bb79ce41552e38b836ad7b6bd1967e60c880f831341ad412699e4a9f5346713a6db2c7032bb7d1b3cc8e42f49ba17000f9d0916a13f2debf000f1ce88af88b96aaeb0104d4c966303eb9609df1b851a0d6149d05bba82f3fd70820a26d7f9d6fe18a7653fd3e3eda94fd9184726dadd2e8d58d09a8473e919f0800104583407293c41bef15c05ac20fc45fd5f9d00639c5b1f738d1ba42cd290fe5291e05219cefa8568806bfc1de76bcf5f799c90c9c6dd54bd69f9d459e994acb7a00110638c8067b42005ae678a7619e9eaad5fb66f0630547ab252179668e60b738c479ba6ff7e1f3dcffddab15e1bfebf93e0e4cb051535bdda3ecef6620aea32132016866e56400000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000008813690014155575600000000000d8ec4750000271098d4f856e398eb41afbd0f2b24ad80e58b1f57b601005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009fdcc9378c600000001105b4d5afffffff8000000006866e564000000006866e564000009fbf79e7bc000000000e99c0d1c0c02b95abadee324fbb6534576de1507c74c8ddef2b928c314cb3d4978a5ada03db907df05ba0fc051e659facec6479c324c276e5098fde9dcae0b462cd32d9e2e5b617b51ced85d38a8456022f3ab370d3c45a07acb686cfb39976b2f4bb1007a91e599951ed929f714a04dab0e6bd885a0c91a076f3b83ee8f765b70a3edda569876102f2c62cae15024e529a2e5e17c50411aa736c7511278a92f4d9cdda3239057c3a942a1365a58771734a982e41e1d7aa8bae87748f1becd045fcb5e1cb1993e978168147d6be8a2cba24a3cc8a2f78e7313f18c87ec2bb238510ebeb47aab50a449fd2ce3dc6b8c0d08d361c102"; + // 0x879551021853eec7a7dc827578e8e69da7e4fa8148339aa0d3d5296405be4b1a + let hex_str = "504e41550100000003b801000000040d02f11b16ae1042344f3c25ea3738f48985f16ed9ebd2e6a21c0b3ffc95f47f327d0afabe6c452b65ec71345b84ce9efb933c77c76285cb43c50bdc7c8fb6bef58d01036c7d8bb399c1fb786cf9ead5d604d4b8739f477a5d4a543ebec13309cdbc28926b4b1a84447431e818576f129d3c1a0ac42f43a4f6cc98607a8ab9173116714c0004181f8d49fc6d4943ccce639da721ccea067e049cf2be33dd4c002ec2185993ba498006814f42b8d949fe95fa1c39ff899ba694902ca0d60ad2cd6fbd86642bea0006f9bc4c86125c6ea76637f4e9afb7c4fe1b1f7669ad6454f7af2b1964cc11b7ec754709960ac5eb9165bba6e54482c9c2835ee67c99f4a1694cdfd05811c0c3630108b6805cd6aa6bd074a59bfe68c10016bc7acbbf61ca936fa1356ecd782493cb4f328964a4055938c77646cbdfc7487be8ded6f285507ba986f39c3aa584be3b67010a32f69176149696a1b503434c25456a41dd86582c5f07f305d9f3b4b14cb3eea30045e996df3fc016e9213e19b5f19a2896cd8c9aa52ba931cedc6f3672c92856010b55e38782b6df0e1926ac5708e0bd60a7f85fee986d54544a683eb8d0855d1d485a96066f773951d6106098bfdcb1c1ae8165bed84126a539747633c87a9e6cb0010d5b5d539c768dba043adb35641b5e7b1e14e30ddd3db2cb4d3b2ee540c5db04cd0eb244ad60a9fbeac1555795c1377e2e3cae70961e241e499a3404cdc7358662000e553a69464feeceb4be71ac5a55b50f60403f23d764debfdc002edef342c927fc6c161a4eebc6be95e014fcda76c537335578228a206b9715b57747a65335b9bd010f3e4971a7f76c0e7160bf236d9a62af81735f25f4067a31b836c36608073b1cf35c918b30c03bbfa2c30de7ad54bcd293f38ac7d360efe9079590e81d2b4affe00110d812f635ebb9b8faeee88405469a554792ddfcc3353137cb820c361c893b2fbf4a7a308194be096e00d3514449c3bbf3c638a6af92962cc30bf0323f0dd535cb011106306af0986424de86434aaba4dc11ce5e08a1a15722c065dd4fa3ca36d5859230e0eea8cc74b31fc024f025956121374f1354a742eec364cdf0079ca885e39d01123dc4dcfae02cbd590e7a4d85a07b2e9a107ffb95fed0c843af6b7b884eddc8d05925fb1d271e2bf3c41970d9f83bfd82cefc7d45c143c7595352ced45bd2dbef016870024200000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71000000000897747c014155575600000000000da502fd000027102a19430cad54e27fe63ae1b4743caf77ff8ed43c01005500a6320c8329924601f4d092dd3f562376f657fa0b5d0cba9e4385a24aaf135384000000000062b4b2000000000000324bfffffff8000000006870024200000000687002420000000000622f4000000000000038df0c1c5dde54a2e342f851ea9041fafbcd1a6b2f1b76d54a4216f1d2441a666411a011ce756da5bf4b599f7faa456612f1810aa04f46e929405e6fd2704f4576157213ea8a656558e788f104832754f6ae3a5481df8f57e0f6ab6043a5de784086ce07e102ad4eb961b86e29ede26cd32a7dff934b7848844b4eb75f109aa8f1c411a4d2c23413fdb33a260c913c3a35df074c9a2590e8513caa5400001c9abe9a640200d17f8f18307c1d757dd8fa7aac510b57ed3cccaeba6f36e6ea506783cfb726d644e8b9f19dcb1e599ced6dd9a3b558e83124753869d08dd7fa85568c579dc2a4b9bdd0e7876994aa18cc8a57eecb"; let bytes = Vec::from_hex(hex_str).expect("Invalid hex string"); vec![bytes] } +#[cfg(test)] +pub fn good_update1_feed_id() -> [u8; 32] { + let hex_string = "a6320c8329924601f4d092dd3f562376f657fa0b5d0cba9e4385a24aaf135384"; + let bytes_vec = hex::decode(hex_string).expect("Invalid hex string"); + + let byte_array: [u8; 32] = bytes_vec + .try_into() + .expect("Hex string must decode to exactly 32 bytes"); + byte_array +} + #[cfg(test)] pub fn multiple_updates_same_vaa() -> Vec> { let hex_str = "504e41550100000003b801000000040d02e57b0f291daa4d2f02f5c4a18793b278b238338f472d17897f8f0866549f77571cfe71fa55bae7f340b9124511559b73a0cf01c72adc8a8d9963cebecc5a503801039507a96b155046ab039f7c9cad17a4927e2ff34763bca9b65d572ddc7a5f019832ffbeeb5295447bfdb989efa0314865bb4571770ad8e75ae7a083288d6de232010412e7333ab5cf0f20274b0907da43b52016d5a095bb846962d13a222e4af1e7e63f7a8db49de04feb70f07a0e274dc58acc7a4c386a099369412c6813ba39916100063da672f75cf1d397829a39461e311ca366366828be8d12b19a00c552e7c8c5e7746b36d97dccc54e5b3aeae188b372ec885dc1fbd9c2285ce458764c86f0c1bb0008863aa237e9fe339683992121249a2e520b6483a3b3b60c703a1eb09ef33266312e729ff6d398e1a60be8474a95803cd1641ef6c1de2c74f3cd7e1f2510c919f9000a3bd5ec58424b21c48552c3be0f9cccd6e6c641eee2b4e550fb88cc93cfdf10c7409344ec3e81df711a293baba565a85e620d20028d9738e53939fa52f19ce622010b000f803511f89f02610fbece34fe327afb55196cc3e522bb28d71d6e4d5523ac77ca1afbbd8a28b4fe05c7f2aa1c3f428c89fe21096ba67bc505cbfa6ead9808010c315b34c9cac03647df4e12a050f8b739763498aa23999244036e09010e2a79a46d0cbabc22c535542896bc22df05dc5480db06a370dffeb0814424870fd50c21000d4a562686000b65df4e0ca00d2e00d10db9e913b481337ee1c80bb47b25553afb693d7be0c17f6fb106909a1eed52a6c27739471b719d4c450b99b066a02bd2c9010e309508bc7128030ca4b19fc34c0ee0e62eebb549c759c2e8ccfdf062793e41e935754ae1d5356ba98446fa2eaa837ae4b413d1ccdf1af6d9060a2885f18c19e1010f3e2ff50704a6ad1b491cb93a1e4678c0f58b91540ba3ce3b4424c96abbe922562c924debb3336ab2fe835237f16912d768e6e5b739f2ab44b57a1e2607c9bb89001070d0dfac758a38342b107870b4d5761df9e785c6be589317c4b1dad3c08998f11214c29201d172b278aa6f4d57171f0f05fb7a2718e6da6df4449e8897c0c2ac0011d9e885989fa2363ec311bf4e9ebd8738d4b3ecaf9a31c09ce06f9876c3ab772034c1df9ca09c847ee81de80a1f0f8592019fa60e55b02b657b8a7c99bee04701016866e28300000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000008812f80014155575600000000000d8ebd6500002710f015dfd43b23aad91dcd4a7a8a113ed2d39233f202005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009fee44efa2300000000e7f6ffe3fffffff8000000006866e283000000006866e283000009fb4f364d0000000000e98d2f400c2704dab60f1b310d567acb60d77a3ce8003a6f564e8e1f567f00f004381d755e160a07372977a99288dcc9c9477cf9c1bb095403b514082aa774f7b243003e30548cbd97e8191d5ef2732796e06f84f05543a171f1e66052aa515c41a2d994a0d13e2e4016e6a28823201a52d408a5024797ec4b7629406062dd9ccc30a5d1eb4ac8b4a28a3d464bf4335ceda7646e03c29cc24b6c7c5e5924e6e69400a2c90561c9a2e4555084af13fbc7eaa0a884b75d4d1197933ac174b62c4b9b1cde3dd496f5e54cd2e01cdca0ba5c5a80a2bbd0d9d5dfb7aab5b638ef883e4e55f78a1536fe79c5c3e16cda9b53e364e3bbe95f005500ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace0000003c480c0e980000000009727f59fffffff8000000006866e283000000006866e2830000003c3597da300000000007d3439a0ccf5f10d7559e184107e994663aa0fc8f81718c0b281162b77eb09c774da30e2db5674df62494b3da820f6c986a0f32d1a195b6bc4676891d4e28cdb4e2f09dd47db3243547b37bdbb9799c82a42d6f1f18f8e17d7bed68408ef26e184f21e9b640e2c9f0416d91987acbe6fa8e72c2c99fa548f83c0eb5dd3c269ef52101521ef0b3d26f50b07dae68311bd138338881b20b78f8d21d2bfc27e9ac849b4c659d61c9a2e4555084af13fbc7eaa0a884b75d4d1197933ac174b62c4b9b1cde3dd496f5e54cd2e01cdca0ba5c5a80a2bbd0d9d5dfb7aab5b638ef883e4e55f78a1536fe79c5c3e16cda9b53e364e3bbe95f"; @@ -58,12 +71,24 @@ pub fn multiple_updates_diff_vaa_results() -> [(U64, I32, I64, U64, I64, U64); 2 #[cfg(test)] pub fn good_update1_results() -> (U64, I32, I64, U64, I64, U64) { ( - U64::from(1751563000u64), + U64::from(1752170378u64), + I32::from_le_bytes((-8i32).to_le_bytes()), + I64::from_le_bytes(6512459i64.to_le_bytes()), + U64::from(20759u64), + I64::from_le_bytes(6423048i64.to_le_bytes()), + U64::from(14961u64), + ) +} + +#[cfg(test)] +pub fn good_update2_results() -> (U64, I32, I64, U64, I64, U64) { + ( + U64::from(1752171074u64), I32::from_le_bytes((-8i32).to_le_bytes()), - I64::from_le_bytes(10967241867779i64.to_le_bytes()), - U64::from(4971244966u64), - I64::from_le_bytes(10942391100000i64.to_le_bytes()), - U64::from(4398561400u64), + I64::from_le_bytes(6468786i64.to_le_bytes()), + U64::from(12875u64), + I64::from_le_bytes(6434624i64.to_le_bytes()), + U64::from(14559u64), ) } @@ -89,18 +114,6 @@ pub fn multiple_updates_results() -> [(U64, I32, I64, U64, I64, U64); 2] { ] } -#[cfg(test)] -pub fn good_update2_results() -> (U64, I32, I64, U64, I64, U64) { - ( - U64::from(1751573860u64), - I32::from_le_bytes((-8i32).to_le_bytes()), - I64::from_le_bytes(10985663592646i64.to_le_bytes()), - U64::from(4569386330u64), - I64::from_le_bytes(10977795800000i64.to_le_bytes()), - U64::from(3919318300u64), - ) -} - #[cfg(test)] pub fn current_guardians() -> Vec
{ vec![ From 7f154bafedae2dc66b781b10f903240a3e19573a Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 10 Jul 2025 18:50:14 +0000 Subject: [PATCH 13/22] feat: modify PriceFeedReturn to use byte arrays and simplify parsing logic - Change PriceFeedReturn from hex string to byte array ([u8; 32], U64, I32, I64, U64, I64, U64) - Update parse_price_feed_updates_internal to return Vec instead of Vec<([u8; 32], PriceFeedReturn)> - Simplify parse_price_feed_updates_with_config by removing price_map and using direct indexing with find() - Simplify update_price_feeds_internal to avoid dual variable iteration and directly index structs - Update test data functions to use byte arrays from helper functions instead of hex strings - Add helper functions for different feed IDs used in multiple updates tests All tests pass successfully with these changes. Co-Authored-By: ayush.suresh@dourolabs.xyz --- .../stylus/contracts/pyth-receiver/src/lib.rs | 54 +++++++++---------- .../contracts/pyth-receiver/src/structs.rs | 2 +- .../contracts/pyth-receiver/src/test_data.rs | 41 ++++++++++++-- 3 files changed, 63 insertions(+), 34 deletions(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs index cc404cf8c5..da088d0930 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs @@ -121,6 +121,7 @@ impl PythReceiver { } Ok(( + id, price_info.publish_time.get(), price_info.expo.get(), price_info.price.get(), @@ -136,7 +137,7 @@ impl PythReceiver { age: u64, ) -> Result { 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.1, age) { return Err(PythReceiverError::NewPriceUnavailable); } Ok(price_info) @@ -151,6 +152,7 @@ impl PythReceiver { } Ok(( + id, price_info.publish_time.get(), price_info.expo.get(), price_info.ema_price.get(), @@ -166,7 +168,7 @@ impl PythReceiver { age: u64, ) -> Result { 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.1, age) { return Err(PythReceiverError::NewPriceUnavailable); } Ok(price_info) @@ -226,31 +228,31 @@ impl PythReceiver { min_publish_time: u64, max_publish_time: u64, _unique: bool, - ) -> Result, PythReceiverError> { - let price_pairs = self.parse_price_feed_updates_internal( + ) -> Result, PythReceiverError> { + let price_feeds = self.parse_price_feed_updates_internal( update_data, min_publish_time, max_publish_time, false, // check_uniqueness )?; - for (price_id, price_return) in price_pairs.clone() { - let price_id_fb: FixedBytes<32> = FixedBytes::from(price_id); + for price_return in &price_feeds { + 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.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); } } - Ok(price_pairs) + Ok(price_feeds) } fn get_update_fee(&self, update_data: Vec>) -> Result { @@ -308,10 +310,10 @@ impl PythReceiver { check_update_data_is_minimal: bool, store_updates_if_fresh: bool, ) -> Result, PythReceiverError> { - let mut all_parsed_price_pairs = Vec::new(); + 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(), price_ids.clone(), min_allowed_publish_time, @@ -319,7 +321,7 @@ impl PythReceiver { 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, @@ -328,22 +330,15 @@ 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 = Vec::with_capacity(price_ids.len()); - let mut price_map: BTreeMap<[u8; 32], PriceFeedReturn> = 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); - } - } 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); } @@ -358,7 +353,7 @@ impl PythReceiver { min_allowed_publish_time: u64, max_allowed_publish_time: u64, check_uniqueness: bool, - ) -> Result, PythReceiverError> { + ) -> Result, 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 { @@ -444,6 +439,7 @@ impl PythReceiver { } let price_info_return = ( + price_feed_message.feed_id, 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()), @@ -462,7 +458,7 @@ impl PythReceiver { } }; - Ok(price_feeds.into_iter().collect()) + Ok(price_feeds.into_iter().map(|(_, price_info)| price_info).collect()) } pub fn parse_twap_price_feed_updates( diff --git a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs b/target_chains/stylus/contracts/pyth-receiver/src/structs.rs index 3f804725db..3adb8ede19 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/structs.rs @@ -57,7 +57,7 @@ pub struct PriceInfoStorage { // pub ema_conf: U64, // } -pub type PriceFeedReturn = (U64, I32, I64, U64, I64, U64); +pub type PriceFeedReturn = ([u8; 32], U64, I32, I64, U64, I64, U64); pub type PriceReturn = ([u8; 32], U64, I32, I64, U64, I64, U64); diff --git a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs index c241bc8da4..009459e5a9 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs @@ -29,6 +29,33 @@ pub fn good_update1_feed_id() -> [u8; 32] { byte_array } +#[cfg(test)] +pub fn multiple_updates_first_feed_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, + ] +} + +#[cfg(test)] +pub fn multiple_updates_second_feed_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, + ] +} + +#[cfg(test)] +pub fn multiple_updates_diff_first_feed_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, + ] +} + #[cfg(test)] pub fn multiple_updates_same_vaa() -> Vec> { let hex_str = "504e41550100000003b801000000040d02e57b0f291daa4d2f02f5c4a18793b278b238338f472d17897f8f0866549f77571cfe71fa55bae7f340b9124511559b73a0cf01c72adc8a8d9963cebecc5a503801039507a96b155046ab039f7c9cad17a4927e2ff34763bca9b65d572ddc7a5f019832ffbeeb5295447bfdb989efa0314865bb4571770ad8e75ae7a083288d6de232010412e7333ab5cf0f20274b0907da43b52016d5a095bb846962d13a222e4af1e7e63f7a8db49de04feb70f07a0e274dc58acc7a4c386a099369412c6813ba39916100063da672f75cf1d397829a39461e311ca366366828be8d12b19a00c552e7c8c5e7746b36d97dccc54e5b3aeae188b372ec885dc1fbd9c2285ce458764c86f0c1bb0008863aa237e9fe339683992121249a2e520b6483a3b3b60c703a1eb09ef33266312e729ff6d398e1a60be8474a95803cd1641ef6c1de2c74f3cd7e1f2510c919f9000a3bd5ec58424b21c48552c3be0f9cccd6e6c641eee2b4e550fb88cc93cfdf10c7409344ec3e81df711a293baba565a85e620d20028d9738e53939fa52f19ce622010b000f803511f89f02610fbece34fe327afb55196cc3e522bb28d71d6e4d5523ac77ca1afbbd8a28b4fe05c7f2aa1c3f428c89fe21096ba67bc505cbfa6ead9808010c315b34c9cac03647df4e12a050f8b739763498aa23999244036e09010e2a79a46d0cbabc22c535542896bc22df05dc5480db06a370dffeb0814424870fd50c21000d4a562686000b65df4e0ca00d2e00d10db9e913b481337ee1c80bb47b25553afb693d7be0c17f6fb106909a1eed52a6c27739471b719d4c450b99b066a02bd2c9010e309508bc7128030ca4b19fc34c0ee0e62eebb549c759c2e8ccfdf062793e41e935754ae1d5356ba98446fa2eaa837ae4b413d1ccdf1af6d9060a2885f18c19e1010f3e2ff50704a6ad1b491cb93a1e4678c0f58b91540ba3ce3b4424c96abbe922562c924debb3336ab2fe835237f16912d768e6e5b739f2ab44b57a1e2607c9bb89001070d0dfac758a38342b107870b4d5761df9e785c6be589317c4b1dad3c08998f11214c29201d172b278aa6f4d57171f0f05fb7a2718e6da6df4449e8897c0c2ac0011d9e885989fa2363ec311bf4e9ebd8738d4b3ecaf9a31c09ce06f9876c3ab772034c1df9ca09c847ee81de80a1f0f8592019fa60e55b02b657b8a7c99bee04701016866e28300000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000008812f80014155575600000000000d8ebd6500002710f015dfd43b23aad91dcd4a7a8a113ed2d39233f202005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009fee44efa2300000000e7f6ffe3fffffff8000000006866e283000000006866e283000009fb4f364d0000000000e98d2f400c2704dab60f1b310d567acb60d77a3ce8003a6f564e8e1f567f00f004381d755e160a07372977a99288dcc9c9477cf9c1bb095403b514082aa774f7b243003e30548cbd97e8191d5ef2732796e06f84f05543a171f1e66052aa515c41a2d994a0d13e2e4016e6a28823201a52d408a5024797ec4b7629406062dd9ccc30a5d1eb4ac8b4a28a3d464bf4335ceda7646e03c29cc24b6c7c5e5924e6e69400a2c90561c9a2e4555084af13fbc7eaa0a884b75d4d1197933ac174b62c4b9b1cde3dd496f5e54cd2e01cdca0ba5c5a80a2bbd0d9d5dfb7aab5b638ef883e4e55f78a1536fe79c5c3e16cda9b53e364e3bbe95f005500ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace0000003c480c0e980000000009727f59fffffff8000000006866e283000000006866e2830000003c3597da300000000007d3439a0ccf5f10d7559e184107e994663aa0fc8f81718c0b281162b77eb09c774da30e2db5674df62494b3da820f6c986a0f32d1a195b6bc4676891d4e28cdb4e2f09dd47db3243547b37bdbb9799c82a42d6f1f18f8e17d7bed68408ef26e184f21e9b640e2c9f0416d91987acbe6fa8e72c2c99fa548f83c0eb5dd3c269ef52101521ef0b3d26f50b07dae68311bd138338881b20b78f8d21d2bfc27e9ac849b4c659d61c9a2e4555084af13fbc7eaa0a884b75d4d1197933ac174b62c4b9b1cde3dd496f5e54cd2e01cdca0ba5c5a80a2bbd0d9d5dfb7aab5b638ef883e4e55f78a1536fe79c5c3e16cda9b53e364e3bbe95f"; @@ -47,9 +74,10 @@ pub fn multiple_updates_diff_vaa() -> Vec> { } #[cfg(test)] -pub fn multiple_updates_diff_vaa_results() -> [(U64, I32, I64, U64, I64, U64); 2] { +pub fn multiple_updates_diff_vaa_results() -> [([u8; 32], U64, I32, I64, U64, I64, U64); 2] { [ ( + multiple_updates_diff_first_feed_id(), U64::from(1752094858u64), I32::from_le_bytes((-8i32).to_le_bytes()), I64::from_le_bytes(35134945i64.to_le_bytes()), @@ -58,6 +86,7 @@ pub fn multiple_updates_diff_vaa_results() -> [(U64, I32, I64, U64, I64, U64); 2 U64::from(35632u64), ), ( + multiple_updates_first_feed_id(), U64::from(1751573860u64), I32::from_le_bytes((-8i32).to_le_bytes()), I64::from_le_bytes(10985663592646i64.to_le_bytes()), @@ -69,8 +98,9 @@ pub fn multiple_updates_diff_vaa_results() -> [(U64, I32, I64, U64, I64, U64); 2 } #[cfg(test)] -pub fn good_update1_results() -> (U64, I32, I64, U64, I64, U64) { +pub fn good_update1_results() -> ([u8; 32], U64, I32, I64, U64, I64, U64) { ( + good_update1_feed_id(), U64::from(1752170378u64), I32::from_le_bytes((-8i32).to_le_bytes()), I64::from_le_bytes(6512459i64.to_le_bytes()), @@ -81,8 +111,9 @@ pub fn good_update1_results() -> (U64, I32, I64, U64, I64, U64) { } #[cfg(test)] -pub fn good_update2_results() -> (U64, I32, I64, U64, I64, U64) { +pub fn good_update2_results() -> ([u8; 32], U64, I32, I64, U64, I64, U64) { ( + good_update1_feed_id(), U64::from(1752171074u64), I32::from_le_bytes((-8i32).to_le_bytes()), I64::from_le_bytes(6468786i64.to_le_bytes()), @@ -93,9 +124,10 @@ pub fn good_update2_results() -> (U64, I32, I64, U64, I64, U64) { } #[cfg(test)] -pub fn multiple_updates_results() -> [(U64, I32, I64, U64, I64, U64); 2] { +pub fn multiple_updates_results() -> [([u8; 32], U64, I32, I64, U64, I64, U64); 2] { [ ( + multiple_updates_first_feed_id(), U64::from(1751573123u64), I32::from_le_bytes((-8i32).to_le_bytes()), I64::from_le_bytes(10990356724259i64.to_le_bytes()), @@ -104,6 +136,7 @@ pub fn multiple_updates_results() -> [(U64, I32, I64, U64, I64, U64); 2] { U64::from(3918344000u64), ), ( + multiple_updates_second_feed_id(), U64::from(1751573123u64), I32::from_le_bytes((-8i32).to_le_bytes()), I64::from_le_bytes(258906787480i64.to_le_bytes()), From 9fe481a819693baa72630ccb9813baa69ebc8688 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 10 Jul 2025 18:54:17 +0000 Subject: [PATCH 14/22] feat: add price_id field to PriceFeedStorage and rename from PriceInfoStorage - Add price_id field as StorageFixedBytes<32> to PriceInfoStorage struct - Rename PriceInfoStorage to PriceFeedStorage for consistency - Update import statement and storage map declaration in lib.rs - Update update_price_feeds_internal to populate price_id field when storing price data - All tests pass with structural changes Co-Authored-By: ayush.suresh@dourolabs.xyz --- target_chains/stylus/contracts/pyth-receiver/src/lib.rs | 5 +++-- target_chains/stylus/contracts/pyth-receiver/src/structs.rs | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs index da088d0930..b8cc4a7523 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs @@ -39,7 +39,7 @@ use pythnet_sdk::{ }, }, }; -use structs::{DataSource, DataSourceStorage, PriceFeedReturn, PriceInfoStorage}; +use structs::{DataSource, DataSourceStorage, PriceFeedReturn, PriceFeedStorage}; 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, PriceInfoStorage>, + pub latest_price_info: StorageMap, PriceFeedStorage>, pub transaction_fee_in_wei: StorageU256, } @@ -243,6 +243,7 @@ impl PythReceiver { if recent_price_info.publish_time.get() < price_return.1 || recent_price_info.price.get() == I64::ZERO { + 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); diff --git a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs b/target_chains/stylus/contracts/pyth-receiver/src/structs.rs index 3adb8ede19..da2ee9328e 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs +++ b/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, From 1aee40ced8999d31d0eab15f883538c27543784b Mon Sep 17 00:00:00 2001 From: Ayush Suresh Date: Thu, 10 Jul 2025 14:07:22 -0500 Subject: [PATCH 15/22] finished adding id back to return type, distinguishing between get return type and the overall price feed return that will be given from the query function --- .../pyth-receiver/src/integration_tests.rs | 14 +-- .../stylus/contracts/pyth-receiver/src/lib.rs | 24 ++-- .../contracts/pyth-receiver/src/structs.rs | 3 +- .../contracts/pyth-receiver/src/test_data.rs | 104 ++++++++++++++---- 4 files changed, 98 insertions(+), 47 deletions(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs index a5e747c262..058a96b604 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs @@ -118,7 +118,7 @@ mod test { .sender(alice) .get_price_unsafe(good_update1_feed_id()); assert!(price_result.is_ok()); - assert_eq!(price_result.unwrap(), good_update1_results()); + assert_eq!(price_result.unwrap(), good_update1_results_get_price()); } #[motsu::test] @@ -172,7 +172,7 @@ mod test { .sender(alice) .get_price_unsafe(good_update1_feed_id()); assert!(price_result.is_ok()); - assert_eq!(price_result.unwrap(), good_update2_results()); + assert_eq!(price_result.unwrap(), good_update2_results_get_price()); } #[motsu::test] @@ -241,7 +241,7 @@ mod test { .sender(alice) .get_price_no_older_than(good_update1_feed_id(), u64::MAX); assert!(price_result.is_ok()); - assert_eq!(price_result.unwrap(), good_update2_results()); + assert_eq!(price_result.unwrap(), good_update2_results_get_price()); } #[motsu::test] @@ -304,11 +304,11 @@ mod test { 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_results()[0]); + assert_eq!(first_price_result.unwrap(), multiple_updates_results_get_price()[0]); let second_price_result = pyth_contract.sender(alice).get_price_unsafe(second_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_results_get_price()[1]); } #[motsu::test] @@ -340,14 +340,14 @@ mod test { assert!(first_price_result.is_ok()); assert_eq!( first_price_result.unwrap(), - multiple_updates_diff_vaa_results()[0] + multiple_updates_diff_vaa_results_get_price()[0] ); let second_price_result = pyth_contract.sender(alice).get_price_unsafe(second_id); assert!(second_price_result.is_ok()); assert_eq!( second_price_result.unwrap(), - multiple_updates_diff_vaa_results()[1] + multiple_updates_diff_vaa_results_get_price()[1] ); } diff --git a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs index b8cc4a7523..8045093795 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs @@ -39,7 +39,7 @@ use pythnet_sdk::{ }, }, }; -use structs::{DataSource, DataSourceStorage, PriceFeedReturn, PriceFeedStorage}; +use structs::{DataSource, DataSourceStorage, PriceFeedReturn, PriceInfoStorage, PriceReturn}; use wormhole_vaas::{Readable, Vaa, Writeable}; sol_interface! { @@ -111,7 +111,7 @@ impl PythReceiver { } } - pub fn get_price_unsafe(&self, id: [u8; 32]) -> Result { + pub fn get_price_unsafe(&self, id: [u8; 32]) -> Result { let id_fb = FixedBytes::<32>::from(id); let price_info = self.latest_price_info.get(id_fb); @@ -121,13 +121,10 @@ impl PythReceiver { } Ok(( - id, - 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(), + price_info.expo.get(), + price_info.publish_time.get(), )) } @@ -135,7 +132,7 @@ impl PythReceiver { &self, id: [u8; 32], age: u64, - ) -> Result { + ) -> Result { let price_info = self.get_price_unsafe(id)?; if !self.is_no_older_than(price_info.1, age) { return Err(PythReceiverError::NewPriceUnavailable); @@ -143,7 +140,7 @@ impl PythReceiver { Ok(price_info) } - pub fn get_ema_price_unsafe(&self, id: [u8; 32]) -> Result { + pub fn get_ema_price_unsafe(&self, id: [u8; 32]) -> Result { let id_fb = FixedBytes::<32>::from(id); let price_info = self.latest_price_info.get(id_fb); @@ -152,13 +149,10 @@ impl PythReceiver { } Ok(( - id, - 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(), )) } @@ -166,7 +160,7 @@ impl PythReceiver { &self, id: [u8; 32], age: u64, - ) -> Result { + ) -> Result { let price_info = self.get_ema_price_unsafe(id)?; if !self.is_no_older_than(price_info.1, age) { return Err(PythReceiverError::NewPriceUnavailable); diff --git a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs b/target_chains/stylus/contracts/pyth-receiver/src/structs.rs index da2ee9328e..e405994171 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/structs.rs @@ -60,7 +60,8 @@ pub struct PriceFeedStorage { pub type PriceFeedReturn = ([u8; 32], U64, I32, I64, U64, I64, U64); -pub type PriceReturn = ([u8; 32], U64, I32, I64, U64, I64, U64); +// (price, conf, expo, publish_time) +pub type PriceReturn = (I64, U64, I32, U64); #[cfg(test)] mod tests { diff --git a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs index 009459e5a9..1a4015b5d4 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs @@ -74,7 +74,57 @@ pub fn multiple_updates_diff_vaa() -> Vec> { } #[cfg(test)] -pub fn multiple_updates_diff_vaa_results() -> [([u8; 32], U64, I32, I64, U64, I64, U64); 2] { +pub fn good_update1_results_full() -> ([u8; 32], U64, I32, I64, U64, I64, U64) { + ( + good_update1_feed_id(), + U64::from(1752170378u64), + I32::from_le_bytes((-8i32).to_le_bytes()), + I64::from_le_bytes(6512459i64.to_le_bytes()), + U64::from(20759u64), + I64::from_le_bytes(6423048i64.to_le_bytes()), + U64::from(14961u64), + ) +} + +#[cfg(test)] +pub fn good_update2_results_full() -> ([u8; 32], U64, I32, I64, U64, I64, U64) { + ( + good_update1_feed_id(), + U64::from(1752171074u64), + I32::from_le_bytes((-8i32).to_le_bytes()), + I64::from_le_bytes(6468786i64.to_le_bytes()), + U64::from(12875u64), + I64::from_le_bytes(6434624i64.to_le_bytes()), + U64::from(14559u64), + ) +} + +#[cfg(test)] +pub fn multiple_updates_results_full() -> [([u8; 32], U64, I32, I64, U64, I64, U64); 2] { + [ + ( + multiple_updates_first_feed_id(), + U64::from(1751573123u64), + I32::from_le_bytes((-8i32).to_le_bytes()), + I64::from_le_bytes(10990356724259i64.to_le_bytes()), + U64::from(3891724259u64), + I64::from_le_bytes(10974970400000i64.to_le_bytes()), + U64::from(3918344000u64), + ), + ( + multiple_updates_second_feed_id(), + U64::from(1751573123u64), + I32::from_le_bytes((-8i32).to_le_bytes()), + I64::from_le_bytes(258906787480i64.to_le_bytes()), + U64::from(158498649u64), + I64::from_le_bytes(258597182000i64.to_le_bytes()), + U64::from(131285914u64), + ), + ] +} + +#[cfg(test)] +pub fn multiple_updates_diff_vaa_results_full() -> [([u8; 32], U64, I32, I64, U64, I64, U64); 2] { [ ( multiple_updates_diff_first_feed_id(), @@ -98,51 +148,57 @@ pub fn multiple_updates_diff_vaa_results() -> [([u8; 32], U64, I32, I64, U64, I6 } #[cfg(test)] -pub fn good_update1_results() -> ([u8; 32], U64, I32, I64, U64, I64, U64) { +pub fn good_update1_results_get_price() -> (I64, U64, I32, U64) { ( - good_update1_feed_id(), - U64::from(1752170378u64), - I32::from_le_bytes((-8i32).to_le_bytes()), I64::from_le_bytes(6512459i64.to_le_bytes()), U64::from(20759u64), - I64::from_le_bytes(6423048i64.to_le_bytes()), - U64::from(14961u64), + I32::from_le_bytes((-8i32).to_le_bytes()), + U64::from(1752170378u64), ) } #[cfg(test)] -pub fn good_update2_results() -> ([u8; 32], U64, I32, I64, U64, I64, U64) { +pub fn good_update2_results_get_price() -> (I64, U64, I32, U64) { ( - good_update1_feed_id(), - U64::from(1752171074u64), - I32::from_le_bytes((-8i32).to_le_bytes()), I64::from_le_bytes(6468786i64.to_le_bytes()), U64::from(12875u64), - I64::from_le_bytes(6434624i64.to_le_bytes()), - U64::from(14559u64), + I32::from_le_bytes((-8i32).to_le_bytes()), + U64::from(1752171074u64), ) } #[cfg(test)] -pub fn multiple_updates_results() -> [([u8; 32], U64, I32, I64, U64, I64, U64); 2] { +pub fn multiple_updates_results_get_price() -> [(I64, U64, I32, U64); 2] { [ ( - multiple_updates_first_feed_id(), - U64::from(1751573123u64), - I32::from_le_bytes((-8i32).to_le_bytes()), I64::from_le_bytes(10990356724259i64.to_le_bytes()), U64::from(3891724259u64), - I64::from_le_bytes(10974970400000i64.to_le_bytes()), - U64::from(3918344000u64), + I32::from_le_bytes((-8i32).to_le_bytes()), + U64::from(1751573123u64), ), ( - multiple_updates_second_feed_id(), - U64::from(1751573123u64), - I32::from_le_bytes((-8i32).to_le_bytes()), I64::from_le_bytes(258906787480i64.to_le_bytes()), U64::from(158498649u64), - I64::from_le_bytes(258597182000i64.to_le_bytes()), - U64::from(131285914u64), + I32::from_le_bytes((-8i32).to_le_bytes()), + U64::from(1751573123u64), + ), + ] +} + +#[cfg(test)] +pub fn multiple_updates_diff_vaa_results_get_price() -> [(I64, U64, I32, U64); 2] { + [ + ( + I64::from_le_bytes(35134945i64.to_le_bytes()), + U64::from(36279u64), + I32::from_le_bytes((-8i32).to_le_bytes()), + U64::from(1752094858u64), + ), + ( + I64::from_le_bytes(10985663592646i64.to_le_bytes()), + U64::from(4569386330u64), + I32::from_le_bytes((-8i32).to_le_bytes()), + U64::from(1751573860u64), ), ] } From 1c82321f4022014918e400fe0fbf61e47a0e9d48 Mon Sep 17 00:00:00 2001 From: Ayush Suresh Date: Thu, 10 Jul 2025 14:07:38 -0500 Subject: [PATCH 16/22] format --- .../pyth-receiver/src/integration_tests.rs | 10 ++++++++-- .../stylus/contracts/pyth-receiver/src/lib.rs | 14 +++++++++++--- .../contracts/pyth-receiver/src/test_data.rs | 12 ++++++------ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs index 058a96b604..dff2e3571b 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs @@ -304,11 +304,17 @@ mod test { 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_results_get_price()[0]); + assert_eq!( + first_price_result.unwrap(), + multiple_updates_results_get_price()[0] + ); let second_price_result = pyth_contract.sender(alice).get_price_unsafe(second_id); assert!(second_price_result.is_ok()); - assert_eq!(second_price_result.unwrap(), multiple_updates_results_get_price()[1]); + assert_eq!( + second_price_result.unwrap(), + multiple_updates_results_get_price()[1] + ); } #[motsu::test] diff --git a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs index 8045093795..ebaf925616 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs @@ -237,7 +237,9 @@ impl PythReceiver { if recent_price_info.publish_time.get() < price_return.1 || recent_price_info.price.get() == I64::ZERO { - recent_price_info.price_id.set(FixedBytes::from(price_return.0)); + 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); @@ -332,7 +334,10 @@ impl PythReceiver { let mut result: Vec = Vec::with_capacity(price_ids.len()); for price_id in price_ids { - if let Some(price_info) = all_parsed_price_feeds.iter().find(|feed| feed.0 == price_id) { + 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); @@ -453,7 +458,10 @@ impl PythReceiver { } }; - Ok(price_feeds.into_iter().map(|(_, price_info)| price_info).collect()) + Ok(price_feeds + .into_iter() + .map(|(_, price_info)| price_info) + .collect()) } pub fn parse_twap_price_feed_updates( diff --git a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs index 1a4015b5d4..47a52e7017 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs @@ -41,18 +41,18 @@ pub fn multiple_updates_first_feed_id() -> [u8; 32] { #[cfg(test)] pub fn multiple_updates_second_feed_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, + 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, ] } #[cfg(test)] pub fn multiple_updates_diff_first_feed_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, + 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, ] } From 9bd142de873722da6ad46bfa022924881ac35cfd Mon Sep 17 00:00:00 2001 From: Ayush Suresh Date: Thu, 10 Jul 2025 14:10:35 -0500 Subject: [PATCH 17/22] fixed import name error --- target_chains/stylus/contracts/pyth-receiver/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs index ebaf925616..f74aa1d2d9 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs @@ -39,7 +39,7 @@ use pythnet_sdk::{ }, }, }; -use structs::{DataSource, DataSourceStorage, PriceFeedReturn, PriceInfoStorage, PriceReturn}; +use structs::{DataSource, DataSourceStorage, PriceFeedReturn, PriceFeedStorage, PriceReturn}; use wormhole_vaas::{Readable, Vaa, Writeable}; sol_interface! { From fce2f107e77b773ed6066572a7e8371fba31ea1e Mon Sep 17 00:00:00 2001 From: Ayush Suresh Date: Thu, 10 Jul 2025 14:17:54 -0500 Subject: [PATCH 18/22] finished query price feeds function --- .../contracts/pyth-receiver/src/error.rs | 2 + .../stylus/contracts/pyth-receiver/src/lib.rs | 38 ++++++++++++++----- .../contracts/pyth-receiver/src/structs.rs | 2 +- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/error.rs b/target_chains/stylus/contracts/pyth-receiver/src/error.rs index 4b68178d80..caeb2e4922 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/error.rs +++ b/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 for Vec { PythReceiverError::TooManyUpdates => 15, PythReceiverError::PriceFeedNotFoundWithinRange => 16, PythReceiverError::NoFreshUpdate => 17, + PythReceiverError::PriceFeedNotFound => 18, }] } } diff --git a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs index f74aa1d2d9..caeb637a32 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs +++ b/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, @@ -111,6 +111,26 @@ impl PythReceiver { } } + pub fn query_price_feed(&self, id: [u8; 32]) -> Result { + 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(( + id_fb, + 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_unsafe(&self, id: [u8; 32]) -> Result { let id_fb = FixedBytes::<32>::from(id); @@ -370,7 +390,7 @@ impl PythReceiver { let accumulator_update = AccumulatorUpdateData::try_from_slice(&update_data_array) .map_err(|_| PythReceiverError::InvalidAccumulatorMessage)?; - let mut price_feeds: BTreeMap<[u8; 32], PriceFeedReturn> = BTreeMap::new(); + let mut price_feeds = Vec::new(); match accumulator_update.proof { Proof::WormholeMerkle { vaa, updates } => { @@ -424,9 +444,10 @@ 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::(); @@ -439,7 +460,7 @@ impl PythReceiver { } let price_info_return = ( - price_feed_message.feed_id, + 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()), @@ -448,7 +469,7 @@ impl PythReceiver { 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); @@ -458,10 +479,7 @@ impl PythReceiver { } }; - Ok(price_feeds - .into_iter() - .map(|(_, price_info)| price_info) - .collect()) + Ok(price_feeds) } pub fn parse_twap_price_feed_updates( diff --git a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs b/target_chains/stylus/contracts/pyth-receiver/src/structs.rs index e405994171..a6bfdaa448 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/structs.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/structs.rs @@ -58,7 +58,7 @@ pub struct PriceFeedStorage { // pub ema_conf: U64, // } -pub type PriceFeedReturn = ([u8; 32], 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); From d6b04e065a9d63866591bef8acf48c0cf216fb5a Mon Sep 17 00:00:00 2001 From: Ayush Suresh Date: Thu, 10 Jul 2025 14:18:16 -0500 Subject: [PATCH 19/22] formatted --- target_chains/stylus/contracts/pyth-receiver/src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs index caeb637a32..fe8677d693 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs @@ -444,9 +444,8 @@ impl PythReceiver { return Err(PythReceiverError::PriceFeedNotFoundWithinRange); } - let price_id_fb = - FixedBytes::<32>::from(price_feed_message.feed_id); - + let price_id_fb = FixedBytes::<32>::from(price_feed_message.feed_id); + if check_uniqueness { let prev_price_info = self.latest_price_info.get(price_id_fb); let prev_publish_time = From fcd55c417314777827215dc64cdf0164d78a34c6 Mon Sep 17 00:00:00 2001 From: Ayush Suresh Date: Thu, 10 Jul 2025 14:57:08 -0500 Subject: [PATCH 20/22] finished price_feed_exists method --- target_chains/stylus/contracts/pyth-receiver/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs index fe8677d693..06fb5148a9 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs @@ -111,6 +111,12 @@ impl PythReceiver { } } + 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 { let id_fb = FixedBytes::<32>::from(id); From cef812a603c853a9c152091613217a1d7a4a9c68 Mon Sep 17 00:00:00 2001 From: Ayush Suresh Date: Thu, 10 Jul 2025 16:21:30 -0500 Subject: [PATCH 21/22] trying to clean up testing framework --- .../pyth-receiver/src/integration_tests.rs | 159 +++++++++----- .../stylus/contracts/pyth-receiver/src/lib.rs | 6 +- .../contracts/pyth-receiver/src/test_data.rs | 198 +++++------------- 3 files changed, 159 insertions(+), 204 deletions(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs index dff2e3571b..5db46977c5 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs @@ -104,7 +104,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); @@ -116,9 +116,9 @@ mod test { let price_result = pyth_contract .sender(alice) - .get_price_unsafe(good_update1_feed_id()); + .get_price_unsafe(ban_usd_feed_id()); assert!(price_result.is_ok()); - assert_eq!(price_result.unwrap(), good_update1_results_get_price()); + assert_eq!(price_result.unwrap(), ban_usd_results_get_price()); } #[motsu::test] @@ -131,7 +131,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); @@ -150,10 +150,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); @@ -170,9 +170,9 @@ mod test { let price_result = pyth_contract .sender(alice) - .get_price_unsafe(good_update1_feed_id()); + .get_price_unsafe(ban_usd_feed_id()); assert!(price_result.is_ok()); - assert_eq!(price_result.unwrap(), good_update2_results_get_price()); + assert_eq!(price_result.unwrap(), ban_usd_results_get_price()); } #[motsu::test] @@ -185,7 +185,7 @@ mod test { let price_result = pyth_contract .sender(alice) - .get_price_unsafe(good_update1_feed_id()); + .get_price_unsafe(ban_usd_feed_id()); assert!(price_result.is_err()); assert_eq!( price_result.unwrap_err(), @@ -227,7 +227,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); @@ -239,9 +239,9 @@ mod test { let price_result = pyth_contract .sender(alice) - .get_price_no_older_than(good_update1_feed_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_get_price()); + assert_eq!(price_result.unwrap(), btc_usd_results_get_price()); } #[motsu::test] @@ -253,7 +253,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); @@ -265,7 +265,8 @@ mod test { let price_result = pyth_contract .sender(alice) - .get_price_no_older_than(good_update1_feed_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(), @@ -274,14 +275,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, wormhole_contract: Contract, 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); @@ -291,41 +292,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_get_price()[0] + 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_get_price()[1] + 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, wormhole_contract: Contract, 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); @@ -335,35 +333,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_get_price()[0] - ); + #[motsu::test] + fn test_query_price_feed_doesnt_exist( + pyth_contract: Contract, + wormhole_contract: Contract, + 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) + .get_price_unsafe(ban_usd_feed_id()); + + assert!(price_result.is_err()); assert_eq!( - second_price_result.unwrap(), - multiple_updates_diff_vaa_results_get_price()[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, wormhole_contract: Contract, 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, + wormhole_contract: Contract, + 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] + ); } } diff --git a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs index 06fb5148a9..707309bff6 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/lib.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/lib.rs @@ -123,7 +123,7 @@ impl PythReceiver { 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(( @@ -160,7 +160,7 @@ impl PythReceiver { age: u64, ) -> Result { let price_info = self.get_price_unsafe(id)?; - if !self.is_no_older_than(price_info.1, age) { + if !self.is_no_older_than(price_info.3, age) { return Err(PythReceiverError::NewPriceUnavailable); } Ok(price_info) @@ -188,7 +188,7 @@ impl PythReceiver { age: u64, ) -> Result { let price_info = self.get_ema_price_unsafe(id)?; - if !self.is_no_older_than(price_info.1, age) { + if !self.is_no_older_than(price_info.3, age) { return Err(PythReceiverError::NewPriceUnavailable); } Ok(price_info) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs index 47a52e7017..cd5316f642 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/test_data.rs @@ -1,25 +1,10 @@ -use alloy_primitives::{address, Address, I32, I64, U64}; +#[cfg(test)] +use alloy_primitives::{address, Address, FixedBytes, I32, I64, U64}; use hex::FromHex; use std::vec; #[cfg(test)] -pub fn good_update1() -> Vec> { - // 0xa6320c8329924601f4d092dd3f562376f657fa0b5d0cba9e4385a24aaf135384 - let hex_str = "504e41550100000003b801000000040d02cfb65be46a822da31643f7bcce6c632943a0c9bab25872525c640ec1d803832936e560a4d6344c1e98f8fe2714281f882b25bc3e1f5fd3db51a9eae49afe2fb401030f87f6065777bffb27594235323e6680ec24b953ec71f0e0e3708ff28986613b2351aba32024ea226585f90c0a2680ee40786a1978b99596af6c281a947b87bc010492608d288aeaa7393d625111da17271178e739392ac87334b01388897612e63176754d044740d80f8f5511cb92c9925592ca223f8eeea70153ccac10f4f2faee0106944014d7f07eb277fe6cd5b4adf65ec547971ab43cb56a507cb974a059cf5b623e838cb899b2401efdac1d352aabab8d4c737519611f4ae22be6addfb254002c0108e9a6f762c22e639302495af910bf305269f38460360ef32cc4e5b1369d599bd33343d56a8e9b392a8cabfd9fc31bbfa32c03433d14f7b7ecdb1975e9759f3e51010ab4322508f35ca75320715c91ed4bf1b07e89730452e3c25b78469646ea61cdc27e52030b2baed4c91b24c3fa13816d95f70095d6c6cc2e110aaf92bab7e816f7010b48e2366bfbccd42b6b790d618bbe3bae90507be6ffda461a7a42ae19f674e16d359c5743540557f401ba7d33f401d5489d0933c3c6253528d1f9c7df3c51dc11010dcc82f54596cd7fc8dac985d4d1bbe410c82f1846891077783ea8da7522725f4621b51d2c09c008826e70f5b52098669d9a872de47d8544867dc381be6e10af04000eb240c11adf380871403a158fc5ce4482629ae1ca2e8b3ab6e7cf02e20435400d065a6399a49ede59db3ad05e56d5f4d4cfcc2419ce2b21dfd2c6dc955539c66d010f93cf0f4e8db5c1467b72c4d188c3c84faeab9dcb5936c2a4a8e80c8bebe8cbc75bd757243af5f109824e5afb1cafd6995c587cc0714fff8c92b1c109a7f4644d0110a89b1ccda9b5e70e823c259ef21b09ef5dcb3e0599033abdf179292f7395e62f3aead157a15d95377dfec08656f6b3f71e68e7ea8da185c38c6f84e50beb79a8001129768f9183799b4bad3b96953ea53b7ee269cd6763b56051b0fcd93e9f6b62325a811abc9d8d401c3971b864a4a9e1910f3ad6980fccd078b36399df46bd291c00121e92dc37fb15d26237137088d139d6decbb1e1d08a7e2a2acf92eaef9cbd7a93738c702ca0faa0b7764b5a28b4ffe41febeb9c2d62706844e69831b58902d88000686fff8a00000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000008976df2014155575600000000000da4fc6f000027106529465b0781218c3d940e5d11cebff0bc1ef15401005500a6320c8329924601f4d092dd3f562376f657fa0b5d0cba9e4385a24aaf1353840000000000635f4b0000000000005117fffffff800000000686fff8a00000000686fff8a00000000006202080000000000003a710c1957911bdae55923e5b2b971a731b10567748efab84bef5a2e1ac6fbfadd24896a2d225c77a260f03b06cb7c34c3ed018d02ac3fc7eefa997ffc91dc3b50508fb4b11c6c7768bc93dd3abeaf5d912ff895be0136780546fbb2f8b42855afa013d38675d811ab3118f0b0eea13dfd64ceb16649747908f859be12f8116922a05ad919df2bca555e5177ec70ab85278ad68b057e6fdbfe50bc38c3796c43199310760180b3253701d4293f32dc1e9be7f10dc3bf2bbf60ffe85b4e0b9ba3cf87af3c472f5d0372cdec973f4ddee17e89255df7d55bea696c64c7af6e8efd51ec79d1870f4d19bc4d5c65f24bdccd341a7d"; - let bytes = Vec::from_hex(hex_str).expect("Invalid hex string"); - vec![bytes] -} - -#[cfg(test)] -pub fn good_update2() -> Vec> { - // 0x879551021853eec7a7dc827578e8e69da7e4fa8148339aa0d3d5296405be4b1a - let hex_str = "504e41550100000003b801000000040d02f11b16ae1042344f3c25ea3738f48985f16ed9ebd2e6a21c0b3ffc95f47f327d0afabe6c452b65ec71345b84ce9efb933c77c76285cb43c50bdc7c8fb6bef58d01036c7d8bb399c1fb786cf9ead5d604d4b8739f477a5d4a543ebec13309cdbc28926b4b1a84447431e818576f129d3c1a0ac42f43a4f6cc98607a8ab9173116714c0004181f8d49fc6d4943ccce639da721ccea067e049cf2be33dd4c002ec2185993ba498006814f42b8d949fe95fa1c39ff899ba694902ca0d60ad2cd6fbd86642bea0006f9bc4c86125c6ea76637f4e9afb7c4fe1b1f7669ad6454f7af2b1964cc11b7ec754709960ac5eb9165bba6e54482c9c2835ee67c99f4a1694cdfd05811c0c3630108b6805cd6aa6bd074a59bfe68c10016bc7acbbf61ca936fa1356ecd782493cb4f328964a4055938c77646cbdfc7487be8ded6f285507ba986f39c3aa584be3b67010a32f69176149696a1b503434c25456a41dd86582c5f07f305d9f3b4b14cb3eea30045e996df3fc016e9213e19b5f19a2896cd8c9aa52ba931cedc6f3672c92856010b55e38782b6df0e1926ac5708e0bd60a7f85fee986d54544a683eb8d0855d1d485a96066f773951d6106098bfdcb1c1ae8165bed84126a539747633c87a9e6cb0010d5b5d539c768dba043adb35641b5e7b1e14e30ddd3db2cb4d3b2ee540c5db04cd0eb244ad60a9fbeac1555795c1377e2e3cae70961e241e499a3404cdc7358662000e553a69464feeceb4be71ac5a55b50f60403f23d764debfdc002edef342c927fc6c161a4eebc6be95e014fcda76c537335578228a206b9715b57747a65335b9bd010f3e4971a7f76c0e7160bf236d9a62af81735f25f4067a31b836c36608073b1cf35c918b30c03bbfa2c30de7ad54bcd293f38ac7d360efe9079590e81d2b4affe00110d812f635ebb9b8faeee88405469a554792ddfcc3353137cb820c361c893b2fbf4a7a308194be096e00d3514449c3bbf3c638a6af92962cc30bf0323f0dd535cb011106306af0986424de86434aaba4dc11ce5e08a1a15722c065dd4fa3ca36d5859230e0eea8cc74b31fc024f025956121374f1354a742eec364cdf0079ca885e39d01123dc4dcfae02cbd590e7a4d85a07b2e9a107ffb95fed0c843af6b7b884eddc8d05925fb1d271e2bf3c41970d9f83bfd82cefc7d45c143c7595352ced45bd2dbef016870024200000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71000000000897747c014155575600000000000da502fd000027102a19430cad54e27fe63ae1b4743caf77ff8ed43c01005500a6320c8329924601f4d092dd3f562376f657fa0b5d0cba9e4385a24aaf135384000000000062b4b2000000000000324bfffffff8000000006870024200000000687002420000000000622f4000000000000038df0c1c5dde54a2e342f851ea9041fafbcd1a6b2f1b76d54a4216f1d2441a666411a011ce756da5bf4b599f7faa456612f1810aa04f46e929405e6fd2704f4576157213ea8a656558e788f104832754f6ae3a5481df8f57e0f6ab6043a5de784086ce07e102ad4eb961b86e29ede26cd32a7dff934b7848844b4eb75f109aa8f1c411a4d2c23413fdb33a260c913c3a35df074c9a2590e8513caa5400001c9abe9a640200d17f8f18307c1d757dd8fa7aac510b57ed3cccaeba6f36e6ea506783cfb726d644e8b9f19dcb1e599ced6dd9a3b558e83124753869d08dd7fa85568c579dc2a4b9bdd0e7876994aa18cc8a57eecb"; - let bytes = Vec::from_hex(hex_str).expect("Invalid hex string"); - vec![bytes] -} - -#[cfg(test)] -pub fn good_update1_feed_id() -> [u8; 32] { +pub fn ban_usd_feed_id() -> [u8; 32] { let hex_string = "a6320c8329924601f4d092dd3f562376f657fa0b5d0cba9e4385a24aaf135384"; let bytes_vec = hex::decode(hex_string).expect("Invalid hex string"); @@ -30,177 +15,90 @@ pub fn good_update1_feed_id() -> [u8; 32] { } #[cfg(test)] -pub fn multiple_updates_first_feed_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, - ] -} - -#[cfg(test)] -pub fn multiple_updates_second_feed_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, - ] -} - -#[cfg(test)] -pub fn multiple_updates_diff_first_feed_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, - ] -} - -#[cfg(test)] -pub fn multiple_updates_same_vaa() -> Vec> { - let hex_str = "504e41550100000003b801000000040d02e57b0f291daa4d2f02f5c4a18793b278b238338f472d17897f8f0866549f77571cfe71fa55bae7f340b9124511559b73a0cf01c72adc8a8d9963cebecc5a503801039507a96b155046ab039f7c9cad17a4927e2ff34763bca9b65d572ddc7a5f019832ffbeeb5295447bfdb989efa0314865bb4571770ad8e75ae7a083288d6de232010412e7333ab5cf0f20274b0907da43b52016d5a095bb846962d13a222e4af1e7e63f7a8db49de04feb70f07a0e274dc58acc7a4c386a099369412c6813ba39916100063da672f75cf1d397829a39461e311ca366366828be8d12b19a00c552e7c8c5e7746b36d97dccc54e5b3aeae188b372ec885dc1fbd9c2285ce458764c86f0c1bb0008863aa237e9fe339683992121249a2e520b6483a3b3b60c703a1eb09ef33266312e729ff6d398e1a60be8474a95803cd1641ef6c1de2c74f3cd7e1f2510c919f9000a3bd5ec58424b21c48552c3be0f9cccd6e6c641eee2b4e550fb88cc93cfdf10c7409344ec3e81df711a293baba565a85e620d20028d9738e53939fa52f19ce622010b000f803511f89f02610fbece34fe327afb55196cc3e522bb28d71d6e4d5523ac77ca1afbbd8a28b4fe05c7f2aa1c3f428c89fe21096ba67bc505cbfa6ead9808010c315b34c9cac03647df4e12a050f8b739763498aa23999244036e09010e2a79a46d0cbabc22c535542896bc22df05dc5480db06a370dffeb0814424870fd50c21000d4a562686000b65df4e0ca00d2e00d10db9e913b481337ee1c80bb47b25553afb693d7be0c17f6fb106909a1eed52a6c27739471b719d4c450b99b066a02bd2c9010e309508bc7128030ca4b19fc34c0ee0e62eebb549c759c2e8ccfdf062793e41e935754ae1d5356ba98446fa2eaa837ae4b413d1ccdf1af6d9060a2885f18c19e1010f3e2ff50704a6ad1b491cb93a1e4678c0f58b91540ba3ce3b4424c96abbe922562c924debb3336ab2fe835237f16912d768e6e5b739f2ab44b57a1e2607c9bb89001070d0dfac758a38342b107870b4d5761df9e785c6be589317c4b1dad3c08998f11214c29201d172b278aa6f4d57171f0f05fb7a2718e6da6df4449e8897c0c2ac0011d9e885989fa2363ec311bf4e9ebd8738d4b3ecaf9a31c09ce06f9876c3ab772034c1df9ca09c847ee81de80a1f0f8592019fa60e55b02b657b8a7c99bee04701016866e28300000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000008812f80014155575600000000000d8ebd6500002710f015dfd43b23aad91dcd4a7a8a113ed2d39233f202005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009fee44efa2300000000e7f6ffe3fffffff8000000006866e283000000006866e283000009fb4f364d0000000000e98d2f400c2704dab60f1b310d567acb60d77a3ce8003a6f564e8e1f567f00f004381d755e160a07372977a99288dcc9c9477cf9c1bb095403b514082aa774f7b243003e30548cbd97e8191d5ef2732796e06f84f05543a171f1e66052aa515c41a2d994a0d13e2e4016e6a28823201a52d408a5024797ec4b7629406062dd9ccc30a5d1eb4ac8b4a28a3d464bf4335ceda7646e03c29cc24b6c7c5e5924e6e69400a2c90561c9a2e4555084af13fbc7eaa0a884b75d4d1197933ac174b62c4b9b1cde3dd496f5e54cd2e01cdca0ba5c5a80a2bbd0d9d5dfb7aab5b638ef883e4e55f78a1536fe79c5c3e16cda9b53e364e3bbe95f005500ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace0000003c480c0e980000000009727f59fffffff8000000006866e283000000006866e2830000003c3597da300000000007d3439a0ccf5f10d7559e184107e994663aa0fc8f81718c0b281162b77eb09c774da30e2db5674df62494b3da820f6c986a0f32d1a195b6bc4676891d4e28cdb4e2f09dd47db3243547b37bdbb9799c82a42d6f1f18f8e17d7bed68408ef26e184f21e9b640e2c9f0416d91987acbe6fa8e72c2c99fa548f83c0eb5dd3c269ef52101521ef0b3d26f50b07dae68311bd138338881b20b78f8d21d2bfc27e9ac849b4c659d61c9a2e4555084af13fbc7eaa0a884b75d4d1197933ac174b62c4b9b1cde3dd496f5e54cd2e01cdca0ba5c5a80a2bbd0d9d5dfb7aab5b638ef883e4e55f78a1536fe79c5c3e16cda9b53e364e3bbe95f"; +pub fn ban_usd_update() -> Vec> { + let hex_str = "504e41550100000003b801000000040d01c9e767c1685410aa1ad3a221af6d257b01d98301b27b72e78f3d7a8d580a90127451c5c699cbb1ef0b5bfd57645456c2898a997ccd4de6eb79d277ce56a12d0b01027599b2f2450d4d59904dc8f738dd73825db0b5235707b9f44119a84e8632c460652e5d7b3ba142120f2510374a478bd7e5cd71b954cae9ef6ea15d7a08a1c3e90103f3a1bd74938fa7c6b2c917303a002474a5f716501c19789fece2a3f80bd05c457c8087a8b2d14e84762059daa5608e38e4e3e8ed572787a20100b8c1d69777f30104c5640a58148caeab59ed9dcc025f7b7dcdeecbfc51108cc29d3659e8b0a1c1aa4079f43e0e846ed353d45b5f436431096cd3094c2fa15e4920e2d35e33632e00010693790cbfaca431837658775a3b274c05676b272b916245f939e978789874ce0f2daa426325986f38c2ee3b9053008362b60b9851d2e9db69d718faddb96db68700098eafe76c684d04f99292d536de3e95eb446c3fac2f70aaac11d5dbda0b5a38f516b56e9f3472528b675337746653c59ed2eae9079ae7f59c004a8cbb40139a7a010ae14fce0cc71f738ec21e66edcd867db036cd5e11a9476c710d2457e025c035c84518c8750b17197d308b9faa2561ec6532c2266eb36723a9d11871b04e3b1138000ba68cde478a18ebbc8e9c2b4bbb4ff16803d5402efbdc9fc34cad9d9ed6f1609f6c81596fac2eed2b98ce6f5b5d7efba530c8b9c15c70f2f10898b38ea2f9978c000d2ecb926686379023572b64d78aef7f61e9aa3e4ceae1d2b2917c1fae6d112b3d7ad1597e6768fffa2dff61a62012562eb68a7cf5597e9bfe755c280df36aef2c000e293c5cb9c805665057bedcfeae74139f47cb5cddc4d5190bbddc4d12cd53caa972281394ac02759b860382da06e8d9b003285090a6783de21786dfcb3b669c58000f3b90618d7a63cdd7da9e730dbd0bf5b22acdc35c08a17c9a6728b1115e63ff837c3267452dc29d8f77fa0cd39428066ea8ae1fd086293e2f17b9421b59f7922f0010629f08a3a59d8187eefef92a54b9bf55fb676f4e9fea826ffb4aa3331155c2162315bd092dd01776f0e45c5d857f9de70a0cbfa9b33f96d8c752bed5c37cf05600113038bf5593427383bfd0966064dc43f7a84f8c083c1bc1b03aa24fc857008f057778ca2393ac1146bbb51588f4903f0822cb94ac0dce7cdcba3a207969d529d000687028bf00000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71000000000897d17f014155575600000000000da5600300002710bb2be176a294375c4430a694c2813c5823a56bef01005500a6320c8329924601f4d092dd3f562376f657fa0b5d0cba9e4385a24aaf1353840000000000625bef0000000000003c63fffffff800000000687028bf00000000687028bf00000000006223710000000000003c6b0c299b70feaac0e02b6430892ee820e1a0706a4099acf41781c8fa57ba6ca1f0b62d98994ccecb7d465eeae1c5a236df5ea50768f1d8e9300500a8824e608c5a02572ee89aa0f0490bd64d60482516a17a2cf6ef3140ac5e35e3ee1844aeb2fb2ab7740ed0905f80725663f8a7018025ea163ece851177137f0e1012b32a540bbaedd2be2b7ecbb6d7baa37298d5ea1e7d8b6c3e3f3c40ec0cdc546dcac1fc8fd0f16828f8d3d948e4ab67391bbca60a63de48273df382ca02f05bd3aa8a0f7513f2a722bd447d8c07a02e73f14d9bb625e82aea434b9378ffba62dd0ef4d04875b1a31cc077b7a9c58ddd0109e4b67e45"; let bytes = Vec::from_hex(hex_str).expect("Invalid hex string"); vec![bytes] } #[cfg(test)] -pub fn multiple_updates_diff_vaa() -> Vec> { - let hex_str_update_1 = "504e41550100000003b801000000040d0168bad50bb1470e136368ebadeb842cf5256547a30cd65c320a0e476bca15f204326806e4290c004925040f5eea31592c55341936fe7e7537d7b4172f308fc79701033b17478509bf096ebc6107afaaf9f339f68d3ad7ebd9267585cd945b91c93f687550c07d4526dc6f2ad0335c1e849977d91d2e61be04d746a611b444af272a9f0104ce96c5a8d9e4e869c2b7ae54980bf9f315af3d93fe827a346b3b55041e019e982350498c7094c77f09567cd3f2a9961940e304666fb08bfbfac7aa1a6ec157cf010639036dea5439380e1c946f76f06480965b60edf280272ab7f649840e289e3d740e4822619e5608811c66158d22ccdea633961687b3afec2751a53a37b3fd6f4a010a370bf667e0fd0b6df27ae87e94513740d1581ca9eadc15b049b5ce4d96b57ba85f92a7bdc478fde36efd7ab80674048589421fc2644457d7b4e398bc1b5c01f0010bb5ef6559a20289cf9df4a8c076baecd3d8e3567973acf975ee52d0301b8cbddd7bb2e4348fb59020bae2caefd57945cf1107cff7f5fd068079fa59ea27e0e702000cae84bce54e40a0583d8c957ddab0388d053a85622cd83c3de49e4bc4acf515351e118f4c36b903f09fe3afd7ce5499c73c37e80d742fdfbb1a57d7f442f915f7000d90c05b57e9592b303305b0e2a88b05f5b006a5f911ac9feba74c309acbfc3af8270b4d8c0759677db601af1893ec4523f023ee6810070148cd017ca2fe2d5663010e17a7472d37425d9f1505e998736d4138f6f35c620c195340ef87ca0d155cf3aa12fe9c0a9c6341411734dacbc53e36895efa69c9895d682bc6329294a49fd928000fed2cb761a8837d87cf827141eedfeafd1901e38957930bf56cc044ebf2c34e3e06bd8197b10d356236acb2c31be6031b95caf2d7492e2744b176bf8a4a357cb70110f22c1178f5c734e83134432c2f5c76cb6462ccba9db0177640cde08b5413ce09630a9c0d5682ee2a1acca1f5d0a6a3583b9578c6e0fbb2d489e252ec7e5960a90011d984560f66ce62be4ba2512e2d62777429f37d6020f9dcb9a0ac54522f80462b4ff33ab5c832748e50cda01e34eef28271982ac22b216cac2a6bde33a83f6bfd011207131b4a1ab2f2ed984cd444210c5c4147d5da72b27d1fdbf6f1a087141ab6971b20175fd67abc937ad69a42991b780804e67e926a8ca2b218521d6572c394c100686ed88a00000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71000000000894a31a014155575600000000000da2316b00002710d957df1a464d0193bc0c9dd3b555d0544a04623e010055003fa4252848f9f0a1480be62745a4629d9eb1322aebab8a791e344b3b9c1adcf50000000002181de10000000000008db7fffffff800000000686ed88a00000000686ed88a00000000021501d40000000000008b300c29ff39535a48e8f09021a1fee7b9e887d68522dd790970609044b11d98aa7d4beb0d1e390c89ccad2fda83fd5316ad4483fc398b6534be617d42690cc27297ccbf19315c79064275612a0d16a2536fdafaca0648bd28b54a014a468906203c8a9d3deadd4ec12dd380bdd27f9a9bb41a5e841d23671743da3125f40b479518be5250080ac78df8826fb59d02dd07b310b69f954dea12b87cb5aa66af75d3da3f7327578f8ed0c0a7b98d1becad74b16e03ff52eee04497971d9985fd9cc05215490b44499df2c3a64f6fefa743421d947d34de37e185b242db065c8f89e9bb028a3710646273f0721e26c68dbd85fb20"; - let hex_str_update_2 = "504e41550100000003b801000000040d0239010392dab908eb9903d480abf8118d887f2a0c5eaeb9062e6eabab86c1b382127604c63358a7266cc5bade7726e159403c2bf317c7b3a4d8b489bfad4e334301031823d70352d3260226cbdddab0cf7d1584c0e1d23d4358ed12f9620e18a0db2154fbb096ac4cb8d5728e2cecf2b1398d7b9b51954f3fb8b4f59990ce017b0260000495e2691d8e6a0537d8ab3f41b5eb655acde7fbeaea0fdbe1f582383680f54c8a3a697c2c0f8b4110422f1b6beb0bfb601c929148b54dbf85fb19c333ccbb833c00066993a56c5980bf17d2790b933861fffb1fd09618921a90db4ab82cc8b148301f1a55d804d14cb39f648fdb0ef8c9ef1e24edc38d30f2aea7151025240a614bca0008a64a366c59bd6c4ce9d24a0e3beef2a33d28546826b1b969af184a257d648aab5672ad8a9eaf14473da40327e12e5c18168892bcebd693c8bed3df8ee50b85db010a36daa7c639c412969283f83749af93aef2464b27b83914b6026b721a59c8a04446a655686725247bd9154c71ca66505719df5867f775863a788d8bffb1bd637c000b237772560d72da81a782e89b138caf8bf1221b929ead77ca7d178b7b7af1c9141d9e77e22c98fe41b819f023695e6feed6f5215a5cdb6436bf52dc3c4c93e309010c89f2f3c64a8c77ccea47448e7871bbd70b59ed5761e5677458dbe6f82796efa2399e9ad9bf846d88d4688f1d19f9e2adeb2299017baf015c36a811d05c539b86000d6ba11d2f9a0edfd3a4bc23024d18dd010a83803faa79d40aec10a4deee40e8dd3c4c5401118b67bd6d879683cae3ea83d4f9afa744c655775615a7ce34237a02000e09a554d70c0f8e57bb79ce41552e38b836ad7b6bd1967e60c880f831341ad412699e4a9f5346713a6db2c7032bb7d1b3cc8e42f49ba17000f9d0916a13f2debf000f1ce88af88b96aaeb0104d4c966303eb9609df1b851a0d6149d05bba82f3fd70820a26d7f9d6fe18a7653fd3e3eda94fd9184726dadd2e8d58d09a8473e919f0800104583407293c41bef15c05ac20fc45fd5f9d00639c5b1f738d1ba42cd290fe5291e05219cefa8568806bfc1de76bcf5f799c90c9c6dd54bd69f9d459e994acb7a00110638c8067b42005ae678a7619e9eaad5fb66f0630547ab252179668e60b738c479ba6ff7e1f3dcffddab15e1bfebf93e0e4cb051535bdda3ecef6620aea32132016866e56400000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa710000000008813690014155575600000000000d8ec4750000271098d4f856e398eb41afbd0f2b24ad80e58b1f57b601005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43000009fdcc9378c600000001105b4d5afffffff8000000006866e564000000006866e564000009fbf79e7bc000000000e99c0d1c0c02b95abadee324fbb6534576de1507c74c8ddef2b928c314cb3d4978a5ada03db907df05ba0fc051e659facec6479c324c276e5098fde9dcae0b462cd32d9e2e5b617b51ced85d38a8456022f3ab370d3c45a07acb686cfb39976b2f4bb1007a91e599951ed929f714a04dab0e6bd885a0c91a076f3b83ee8f765b70a3edda569876102f2c62cae15024e529a2e5e17c50411aa736c7511278a92f4d9cdda3239057c3a942a1365a58771734a982e41e1d7aa8bae87748f1becd045fcb5e1cb1993e978168147d6be8a2cba24a3cc8a2f78e7313f18c87ec2bb238510ebeb47aab50a449fd2ce3dc6b8c0d08d361c102"; - let bytes_1 = Vec::from_hex(hex_str_update_1).expect("Invalid hex string"); - let bytes_2 = Vec::from_hex(hex_str_update_2).expect("Invalid hex string"); - - vec![bytes_1, bytes_2] -} - -#[cfg(test)] -pub fn good_update1_results_full() -> ([u8; 32], U64, I32, I64, U64, I64, U64) { +pub fn ban_usd_results_full() -> (FixedBytes<32>, U64, I32, I64, U64, I64, U64) { ( - good_update1_feed_id(), - U64::from(1752170378u64), + FixedBytes::<32>::from(ban_usd_feed_id()), + U64::from(1752180927u64), I32::from_le_bytes((-8i32).to_le_bytes()), - I64::from_le_bytes(6512459i64.to_le_bytes()), - U64::from(20759u64), - I64::from_le_bytes(6423048i64.to_le_bytes()), - U64::from(14961u64), + I64::from_le_bytes(6446063i64.to_le_bytes()), + U64::from(15459u64), + I64::from_le_bytes(6431601i64.to_le_bytes()), + U64::from(15467u64), ) } #[cfg(test)] -pub fn good_update2_results_full() -> ([u8; 32], U64, I32, I64, U64, I64, U64) { +pub fn ban_usd_results_get_price() -> (I64, U64, I32, U64) { ( - good_update1_feed_id(), - U64::from(1752171074u64), + I64::from_le_bytes(6446063i64.to_le_bytes()), + U64::from(15459u64), I32::from_le_bytes((-8i32).to_le_bytes()), - I64::from_le_bytes(6468786i64.to_le_bytes()), - U64::from(12875u64), - I64::from_le_bytes(6434624i64.to_le_bytes()), - U64::from(14559u64), + U64::from(1752180927u64), ) } #[cfg(test)] -pub fn multiple_updates_results_full() -> [([u8; 32], U64, I32, I64, U64, I64, U64); 2] { - [ - ( - multiple_updates_first_feed_id(), - U64::from(1751573123u64), - I32::from_le_bytes((-8i32).to_le_bytes()), - I64::from_le_bytes(10990356724259i64.to_le_bytes()), - U64::from(3891724259u64), - I64::from_le_bytes(10974970400000i64.to_le_bytes()), - U64::from(3918344000u64), - ), - ( - multiple_updates_second_feed_id(), - U64::from(1751573123u64), - I32::from_le_bytes((-8i32).to_le_bytes()), - I64::from_le_bytes(258906787480i64.to_le_bytes()), - U64::from(158498649u64), - I64::from_le_bytes(258597182000i64.to_le_bytes()), - U64::from(131285914u64), - ), - ] +pub fn btc_usd_feed_id() -> [u8; 32] { + let hex_string = "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"; + let bytes_vec = hex::decode(hex_string).expect("Invalid hex string"); + + let byte_array: [u8; 32] = bytes_vec + .try_into() + .expect("Hex string must decode to exactly 32 bytes"); + byte_array } #[cfg(test)] -pub fn multiple_updates_diff_vaa_results_full() -> [([u8; 32], U64, I32, I64, U64, I64, U64); 2] { - [ - ( - multiple_updates_diff_first_feed_id(), - U64::from(1752094858u64), - I32::from_le_bytes((-8i32).to_le_bytes()), - I64::from_le_bytes(35134945i64.to_le_bytes()), - U64::from(36279u64), - I64::from_le_bytes(34931156i64.to_le_bytes()), - U64::from(35632u64), - ), - ( - multiple_updates_first_feed_id(), - U64::from(1751573860u64), - I32::from_le_bytes((-8i32).to_le_bytes()), - I64::from_le_bytes(10985663592646i64.to_le_bytes()), - U64::from(4569386330u64), - I64::from_le_bytes(10977795800000i64.to_le_bytes()), - U64::from(3919318300u64), - ), - ] +pub fn btc_usd_update() -> Vec> { + let hex_str = "504e41550100000003b801000000040d0239cafe615bc0f6037d0b2b596490a0473b07ed176082e6645c773678bafd705a3d3e86a03b17c44a9d0e2429051756514c2a247f9d08767b0bf093dd8313814c0103f5be04233a4e4f169428ee7c7e153978c593db55b9fc93ef6329333671eea8c567c143e88300ef470aeb7c3f5fc3d63582fe4c9f28fc451915f0c0a5ac1920f60104883322c38070deaaa013d45ffc4aa111a070938aaed1edda6853fa3676e7fbda6ffcd6711ac4fbb9e9c0320d193b9aace0b1fc42f0060c8ab54024c8cca55e5101066624f81e56e2981619eca215e07e2e055088a2c163dd457bf7d60828b0bc93a27c359999832a0d0534642defc8197b55ffcf1d52b9fcf5a8cee3e73c2910107a01081a8e5f8715f6128642bb34204c08415f972fed334add518e672be983f4e3830b7cdfb653976a37421a86d3ea1d0b5ee2d2baa8c54309539e4e7e64d57f13816d010a0df0714ee3e9d8f741c15b50f2d2b5a80bdfbdcd62963d37efde7690ee2f35ac4a134f425ec84610decb606254c81813d3be6372e64bf7d8692c1ceb7d3dbf31000bdbdfb38a07d2efd68bc96caeb986ab39473d5080575a0f7878bfbd4456da0df25dfad1e45c30bc1eb2d81922a5355db6fbc109b9bf4520f18b2da9cbd06c1b9d010ca5a2450d2339debfb36065567196c340721e260ea524003b2e73ef3f9ed1f9d2446e8b059c91ff124e83156e826c6cb496125ef6f54a578d03de9ce7a488a4f1010d2f389063583770fef355929ec57015b9b7f4d5879f63bc1dd1e8a1605b12cfbf534fb31d56be4e54ae1eba9442045b791b0cc9b56d3e3b0b4e8952c98841bed3000e343679701f31206503ee1014842cffdd7fb6b05173d8373e9fa99bd3a1f075a77339f1a588766d716cf650b7f04c6ec38b4f146932ab19345a5b976beb7fb932010ff8ecf6e31a7588184df483d4db07875c06c009f2837e8402fd5e72fc703317f5284be8d9354b4fab80397828dcee6e8d42e384bc0900e6c09bf03d062449d79b0010804e0a59b1ceaa6b27686390cf012f9b28c3f0631d625a02c2aa61924ae9e3f750d408ba01469ceba5c69750562a8764bf3f395fb2d3651ef7e785880dbf9f6d0011d624fbfc51b33be04143af0df857bff085ec613ce45c0afac19cb7b25d1386d4748a757c1d88c084a5917c0fa29e62777f52627100f9371e17b9cf3d7761e74c006870299c00000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71000000000897d392014155575600000000000da562160000271079aec689f7474fccda868e2c953a8034004c18f001005500e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b4300000a555e80406d00000000d970a713fffffff8000000006870299c000000006870299b00000a51d33b2f20000000010aa6a7740c9ed309739de34ae90fbadd4e31dfb63bdf4e6ce18be268a0b475c9fa239b3b3dc6413e6be59d3e081d18340d5f54f7c775bb8a3624c9b6365c377be3c7d8d95148bbeef8ed7337083c85b99f3d24fceef013b441f91efaf0d75d3054c798046ed109da12b59b60043a81139983cf1c68705c58279e7b3f122ff0562c5e8b925d8ebd8791842efc74260de6917967faea7c994b1bd8791cce3129f877447db2fe0e5436384e4e2dd7facc50127c072a25f69aad5d3c89ed0f38cb6b792c0d12c123f76b7059e9217b959969ba558430b06a4aeb769fd7a1a8cf3eb74680f0bc1b84882fb8e311d3db94ea051d2e209f6b"; + let bytes = Vec::from_hex(hex_str).expect("Invalid hex string"); + vec![bytes] } #[cfg(test)] -pub fn good_update1_results_get_price() -> (I64, U64, I32, U64) { +pub fn btc_usd_results_full() -> (FixedBytes<32>, U64, I32, I64, U64, I64, U64) { ( - I64::from_le_bytes(6512459i64.to_le_bytes()), - U64::from(20759u64), + FixedBytes::<32>::from(btc_usd_feed_id()), + U64::from(1752181148u64), I32::from_le_bytes((-8i32).to_le_bytes()), - U64::from(1752170378u64), + I64::from_le_bytes(11361773961325i64.to_le_bytes()), + U64::from(3648038675u64), + I64::from_le_bytes(11346552500000i64.to_le_bytes()), + U64::from(4473661300u64), ) } #[cfg(test)] -pub fn good_update2_results_get_price() -> (I64, U64, I32, U64) { +pub fn btc_usd_results_get_price() -> (I64, U64, I32, U64) { ( - I64::from_le_bytes(6468786i64.to_le_bytes()), - U64::from(12875u64), + I64::from_le_bytes(11361773961325i64.to_le_bytes()), + U64::from(3648038675u64), I32::from_le_bytes((-8i32).to_le_bytes()), - U64::from(1752171074u64), + U64::from(1752181148u64), ) } #[cfg(test)] -pub fn multiple_updates_results_get_price() -> [(I64, U64, I32, U64); 2] { - [ - ( - I64::from_le_bytes(10990356724259i64.to_le_bytes()), - U64::from(3891724259u64), - I32::from_le_bytes((-8i32).to_le_bytes()), - U64::from(1751573123u64), - ), - ( - I64::from_le_bytes(258906787480i64.to_le_bytes()), - U64::from(158498649u64), - I32::from_le_bytes((-8i32).to_le_bytes()), - U64::from(1751573123u64), - ), - ] +pub fn multiple_updates_diff_vaa() -> Vec> { + vec![ban_usd_update()[0].clone(), btc_usd_update()[0].clone()] +} + +#[cfg(test)] +pub fn multiple_updates_diff_vaa_results_full( +) -> [(FixedBytes<32>, U64, I32, I64, U64, I64, U64); 2] { + [ban_usd_results_full(), btc_usd_results_full()] } #[cfg(test)] pub fn multiple_updates_diff_vaa_results_get_price() -> [(I64, U64, I32, U64); 2] { - [ - ( - I64::from_le_bytes(35134945i64.to_le_bytes()), - U64::from(36279u64), - I32::from_le_bytes((-8i32).to_le_bytes()), - U64::from(1752094858u64), - ), - ( - I64::from_le_bytes(10985663592646i64.to_le_bytes()), - U64::from(4569386330u64), - I32::from_le_bytes((-8i32).to_le_bytes()), - U64::from(1751573860u64), - ), - ] + [ban_usd_results_get_price(), btc_usd_results_get_price()] } #[cfg(test)] From a762be9a5430169982d40b52d93daad92ef67296 Mon Sep 17 00:00:00 2001 From: Ayush Suresh Date: Thu, 10 Jul 2025 16:31:19 -0500 Subject: [PATCH 22/22] fixed test error, all passing --- .../stylus/contracts/pyth-receiver/src/integration_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs index 5db46977c5..dbe7c799f9 100644 --- a/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs +++ b/target_chains/stylus/contracts/pyth-receiver/src/integration_tests.rs @@ -348,7 +348,7 @@ mod test { let price_result = pyth_contract .sender(alice) - .get_price_unsafe(ban_usd_feed_id()); + .query_price_feed(ban_usd_feed_id()); assert!(price_result.is_err()); assert_eq!(