@@ -14,14 +14,21 @@ use stylus_sdk::{alloy_primitives::{U16, U32, U256, U64, I32, I64, FixedBytes, A
14
14
storage:: { StorageGuardMut , StorageAddress , StorageVec , StorageMap , StorageUint , StorageBool , StorageU256 , StorageU16 , StorageFixedBytes } ,
15
15
call:: Call } ;
16
16
17
- use structs:: { PriceInfoReturn , PriceInfoStorage , DataSourceStorage , DataSource } ;
17
+ use structs:: { PriceInfoReturn , PriceInfoStorage , DataSourceStorage , DataSource , PriceInfo } ;
18
18
use error:: { PythReceiverError } ;
19
- use pythnet_sdk:: { wire:: { v1:: {
19
+ use pythnet_sdk:: { wire:: { from_slice , v1:: {
20
20
AccumulatorUpdateData , Proof ,
21
+ PYTHNET_ACCUMULATOR_UPDATE_MAGIC ,
22
+ WormholeMessage , WormholePayload ,
21
23
} ,
22
24
} ,
25
+ accumulators:: { merkle:: { MerklePath , MerkleRoot } } ,
26
+ hashers:: keccak256_160:: Keccak160 ,
27
+ messages:: Message
23
28
} ;
24
- use wormhole_vaas:: { Readable , Vaa , VaaBody , VaaHeader } ;
29
+ use wormhole_vaas:: { Readable , Vaa , VaaBody , VaaHeader , Writeable } ;
30
+
31
+ const ACCUMULATOR_WORMHOLE_MAGIC : u32 = 0x41555756 ;
25
32
26
33
sol_interface ! {
27
34
interface IWormholeContract {
@@ -121,16 +128,45 @@ impl PythReceiver {
121
128
}
122
129
123
130
pub fn update_price_feeds ( & mut self , update_data : Vec < u8 > ) {
131
+
132
+ }
133
+
134
+ pub fn update_price_feeds_if_necessary (
135
+ & mut self ,
136
+ _update_data : Vec < Vec < u8 > > ,
137
+ _price_ids : Vec < [ u8 ; 32 ] > ,
138
+ _publish_times : Vec < u64 > ,
139
+ ) {
140
+ // dummy implementation
141
+ }
142
+
143
+ fn update_price_feeds_internal ( & self , update_data : Vec < u8 > , price_ids : Vec < Address > , min_publish_time : u64 , max_publish_time : u64 , unique : bool ) -> Result < ( ) , PythReceiverError > {
124
144
let update_data_array: & [ u8 ] = & update_data;
125
- let update_data = AccumulatorUpdateData :: try_from_slice ( & update_data_array) . unwrap ( ) ;
145
+ // Check the first 4 bytes of the update_data_array for the magic header
146
+ if update_data_array. len ( ) < 4 {
147
+ panic ! ( "update_data too short for magic header check" ) ;
148
+ }
126
149
150
+ let mut header = [ 0u8 ; 4 ] ;
151
+ header. copy_from_slice ( & update_data_array[ 0 ..4 ] ) ;
152
+
153
+ if & header != PYTHNET_ACCUMULATOR_UPDATE_MAGIC {
154
+ panic ! ( "Invalid update_data magic header" ) ;
155
+ }
156
+
157
+ let update_data = AccumulatorUpdateData :: try_from_slice ( & update_data_array) . unwrap ( ) ;
158
+
127
159
match update_data. proof {
128
160
Proof :: WormholeMerkle { vaa, updates } => {
129
161
let wormhole: IWormholeContract = IWormholeContract :: new ( self . wormhole . get ( ) ) ;
130
- let config = Call :: new_in ( self ) ;
162
+ let config = Call :: new ( ) ;
131
163
let parsed_vaa = wormhole. parse_and_verify_vm ( config, Vec :: from ( vaa) ) . map_err ( |_| PythReceiverError :: PriceUnavailable ) . unwrap ( ) ;
132
164
let vaa = Vaa :: read ( & mut parsed_vaa. as_slice ( ) ) . unwrap ( ) ;
133
165
166
+ // TODO: CHECK IF THE VAA IS FROM A VALID DATA SOURCE
167
+
168
+ let root_digest: MerkleRoot < Keccak160 > = parse_wormhole_proof ( vaa) . unwrap ( ) ;
169
+
134
170
for update in updates {
135
171
// fill in update processing logic.
136
172
// update is a merkle price update
@@ -140,22 +176,44 @@ impl PythReceiver {
140
176
// pub proof: MerklePath<Keccak160>,
141
177
// }
142
178
143
- let message = update. message ;
144
- let proof = update. proof ;
179
+ let message_vec = Vec :: from ( update. message ) ;
180
+ let proof: MerklePath < Keccak160 > = update. proof ;
181
+
182
+ if !root_digest. check ( proof, & message_vec) {
183
+ return Err ( PythReceiverError :: PriceUnavailable ) ;
184
+ }
145
185
186
+ // TODO: UPDATE THE PRICE INFO
187
+ let msg = from_slice :: < byteorder:: BE , Message > ( & message_vec)
188
+ . map_err ( |_| PythReceiverError :: PriceUnavailable ) ?;
146
189
190
+ match msg {
191
+ Message :: PriceFeedMessage ( price_feed_message) => {
192
+ // if self.update_price_feed_if_new(price_feed_message.feed_id,PriceInfoStorage::from(&price_feed_message)) {
193
+ // count_updates += 1;
194
+ // }
195
+
196
+ } ,
197
+ Message :: TwapMessage ( _) => {
198
+ // Handle TWAP message - currently not implemented
199
+ // This could be extended to handle TWAP price updates
200
+ } ,
201
+ Message :: PublisherStakeCapsMessage ( _) => {
202
+ // Handle publisher stake caps message - currently not implemented
203
+ // This could be extended to handle publisher stake updates
204
+ } ,
205
+ }
206
+
207
+
208
+ // TODO: STORE PRICE INFO IN OUTPUT
209
+
147
210
}
211
+
212
+ // TODO: FORM OUTPUT ARRAY
148
213
}
149
214
} ;
150
- }
151
215
152
- pub fn update_price_feeds_if_necessary (
153
- & mut self ,
154
- _update_data : Vec < Vec < u8 > > ,
155
- _price_ids : Vec < [ u8 ; 32 ] > ,
156
- _publish_times : Vec < u64 > ,
157
- ) {
158
- // dummy implementation
216
+ Ok ( ( ) )
159
217
}
160
218
161
219
pub fn get_update_fee ( & self , _update_data : Vec < Vec < u8 > > ) -> U256 {
@@ -213,4 +271,33 @@ impl PythReceiver {
213
271
214
272
current_u64. saturating_sub ( publish_time_u64) <= max_age
215
273
}
274
+
275
+ // Updates the Price Feed only if it is newer than the current one. This function never fails
276
+ // and will either update in-place or not update at all. The return value indicates whether
277
+ // the update was performed or not.
278
+ // fn update_price_feed_if_new(&mut self, price_id: [u8; 32], price_feed: PriceInfo) -> bool {
279
+ // match self.latest_price_info.get(&price_id) {
280
+ // Some(stored_price_feed) => {
281
+ // let update = price_feed.price.publish_time > stored_price_feed.price.publish_time;
282
+ // update.then(|| self.prices.insert(&price_feed.id, &price_feed));
283
+ // update
284
+ // }
285
+
286
+ // None => {
287
+ // self.prices.insert(&price_feed.id, &price_feed);
288
+ // true
289
+ // }
290
+ // }
291
+ // }
292
+
293
+
216
294
}
295
+
296
+ fn parse_wormhole_proof ( vaa : Vaa ) -> Result < MerkleRoot < Keccak160 > , PythReceiverError > {
297
+ let message = WormholeMessage :: try_from_bytes ( vaa. body . payload . to_vec ( ) )
298
+ . map_err ( |_| PythReceiverError :: PriceUnavailable ) ?;
299
+ let root: MerkleRoot < Keccak160 > = MerkleRoot :: new ( match message. payload {
300
+ WormholePayload :: Merkle ( merkle_root) => merkle_root. root ,
301
+ } ) ;
302
+ Ok ( root)
303
+ }
0 commit comments