@@ -100,6 +100,61 @@ contract PythTest is Test, WormholeTestUtils, PythTestUtils {
100100 );
101101 }
102102
103+ // This method divides messages into a couple of batches and creates
104+ // twap updateData for them. It returns the updateData and the updateFee
105+ function createBatchedTwapUpdateDataFromMessagesWithConfig (
106+ PriceFeedMessage[] memory messages ,
107+ MerkleUpdateConfig memory config
108+ ) public returns (bytes [][] memory updateData , uint updateFee ) {
109+ require (messages.length >= 2 , "At least 2 messages required for TWAP " );
110+
111+ // Select first two messages for TWAP calculation
112+ PriceFeedMessage[] memory startMessages = new PriceFeedMessage [](1 );
113+ startMessages[0 ] = messages[0 ];
114+
115+ PriceFeedMessage[] memory endMessages = new PriceFeedMessage [](1 );
116+ endMessages[0 ] = messages[1 ];
117+
118+ // Generate the update data for start and end
119+ bytes [] memory startUpdateData = new bytes [](1 );
120+ startUpdateData[0 ] = generateWhMerkleUpdateWithSource (
121+ startMessages,
122+ config
123+ );
124+
125+ bytes [] memory endUpdateData = new bytes [](1 );
126+ endUpdateData[0 ] = generateWhMerkleUpdateWithSource (
127+ endMessages,
128+ config
129+ );
130+
131+ // Create the updateData array with exactly 2 elements as required by parseTwapPriceFeedUpdates
132+ updateData = new bytes [][](2 );
133+ updateData[0 ] = startUpdateData;
134+ updateData[1 ] = endUpdateData;
135+
136+ // Calculate the update fee
137+ updateFee = pyth.getUpdateFee (updateData[0 ]);
138+ }
139+
140+ function createBatchedTwapUpdateDataFromMessages (
141+ PriceFeedMessage[] memory messages
142+ ) internal returns (bytes [][] memory updateData , uint updateFee ) {
143+ (
144+ updateData,
145+ updateFee
146+ ) = createBatchedTwapUpdateDataFromMessagesWithConfig (
147+ messages,
148+ MerkleUpdateConfig (
149+ MERKLE_TREE_DEPTH,
150+ NUM_GUARDIAN_SIGNERS,
151+ SOURCE_EMITTER_CHAIN_ID,
152+ SOURCE_EMITTER_ADDRESS,
153+ false
154+ )
155+ );
156+ }
157+
103158 /// Testing parsePriceFeedUpdates method.
104159 function testParsePriceFeedUpdatesWorks (uint seed ) public {
105160 setRandSeed (seed);
@@ -309,4 +364,63 @@ contract PythTest is Test, WormholeTestUtils, PythTestUtils {
309364 MAX_UINT64
310365 );
311366 }
367+
368+ function testParseTwapPriceFeedUpdates () public {
369+ // Define a single price ID we'll use for the test
370+ uint numMessages = 1 ;
371+ bytes32 [] memory priceIds = new bytes32 [](numMessages);
372+ priceIds[0 ] = bytes32 (uint256 (1 ));
373+
374+ // Create two PriceFeedMessage instances for the start and end points
375+ PriceFeedMessage[] memory messages = new PriceFeedMessage [](2 );
376+
377+ // Start message
378+ messages[0 ].priceId = priceIds[0 ];
379+ messages[0 ].price = 100 ;
380+ messages[0 ].conf = 10 ;
381+ messages[0 ].expo = - 8 ;
382+ messages[0 ].publishTime = 1000 ;
383+ messages[0 ].prevPublishTime = 900 ;
384+ messages[0 ].emaPrice = 100 ;
385+ messages[0 ].emaConf = 10 ;
386+
387+ // End message
388+ messages[1 ].priceId = priceIds[0 ];
389+ messages[1 ].price = 110 ;
390+ messages[1 ].conf = 8 ;
391+ messages[1 ].expo = - 8 ;
392+ messages[1 ].publishTime = 1100 ;
393+ messages[1 ].prevPublishTime = 1000 ;
394+ messages[1 ].emaPrice = 110 ;
395+ messages[1 ].emaConf = 8 ;
396+
397+ // Create update data for TWAP calculation
398+ (
399+ bytes [][] memory updateData ,
400+ uint updateFee
401+ ) = createBatchedTwapUpdateDataFromMessages (messages);
402+
403+ // log the updateData
404+ console.logBytes (updateData[0 ][0 ]);
405+ console.logBytes (updateData[1 ][0 ]);
406+
407+ // Parse the TWAP updates
408+ PythStructs.TwapPriceFeed[] memory twapPriceFeeds = pyth
409+ .parseTwapPriceFeedUpdates {value: updateFee}(updateData, priceIds);
410+
411+ // Validate basic properties
412+ assertEq (twapPriceFeeds[0 ].id, priceIds[0 ]);
413+ assertEq (twapPriceFeeds[0 ].startTime, uint64 (1000 )); // publishTime start
414+ assertEq (twapPriceFeeds[0 ].endTime, uint64 (1100 )); // publishTime end
415+ assertEq (twapPriceFeeds[0 ].twap.expo, int32 (- 8 )); // expo
416+
417+ // The TWAP price should be the difference in cumulative price divided by the slot difference
418+ assertEq (twapPriceFeeds[0 ].twap.price, int64 (105 ));
419+
420+ // The TWAP conf should be the difference in cumulative conf divided by the slot difference
421+ assertEq (twapPriceFeeds[0 ].twap.conf, uint64 (9 ));
422+
423+ // Validate the downSlotsRatio is 0 in our test implementation
424+ assertEq (twapPriceFeeds[0 ].downSlotsRatio, uint32 (0 ));
425+ }
312426}
0 commit comments