@@ -159,6 +159,8 @@ contract PythTest is Test, WormholeTestUtils, PythTestUtils {
159159        updateData[1 ] =  endUpdateData;
160160
161161        // Calculate the update fee 
162+         // We only charge fee for 1 update even though we need 2 updates to derive TWAP. 
163+         // This is for better UX since user's intention is to get a single TWAP price. 
162164        updateFee =  pyth.getUpdateFee (updateData[0 ]);
163165    }
164166
@@ -451,4 +453,164 @@ contract PythTest is Test, WormholeTestUtils, PythTestUtils {
451453        // Validate the downSlotsRatio is 0 in our test implementation 
452454        assertEq (twapPriceFeeds[0 ].downSlotsRatio, uint32 (0 ));
453455    }
456+ 
457+     function testParseTwapPriceFeedUpdatesRevertsWithInvalidUpdateDataLength  ()
458+         public 
459+     {
460+         bytes32 [] memory  priceIds =  new  bytes32 [](1 );
461+         priceIds[0 ] =  bytes32 (uint256 (1 ));
462+ 
463+         // Create invalid update data with wrong length 
464+         bytes [][] memory  updateData =  new  bytes [][](1 ); // Should be 2 
465+         updateData[0 ] =  new  bytes [](1 );
466+ 
467+         vm.expectRevert (PythErrors.InvalidUpdateData.selector );
468+         pyth.parseTwapPriceFeedUpdates {value: 0 }(updateData, priceIds);
469+     }
470+ 
471+     function testParseTwapPriceFeedUpdatesRevertsWithMismatchedPriceIds  ()
472+         public 
473+     {
474+         bytes32 [] memory  priceIds =  new  bytes32 [](1 );
475+         priceIds[0 ] =  bytes32 (uint256 (1 ));
476+ 
477+         PriceFeedMessage[] memory  messages =  new  PriceFeedMessage [](2 );
478+ 
479+         // Start message with priceId 1 
480+         messages[0 ].priceId =  bytes32 (uint256 (1 ));
481+         messages[0 ].price =  100 ;
482+         messages[0 ].publishTime =  1000 ;
483+         messages[0 ].prevPublishTime =  900 ;
484+ 
485+         // End message with different priceId 2 
486+         messages[1 ].priceId =  bytes32 (uint256 (2 )); // Different priceId 
487+         messages[1 ].price =  110 ;
488+         messages[1 ].publishTime =  1100 ;
489+         messages[1 ].prevPublishTime =  1000 ;
490+ 
491+         (
492+             bytes [][] memory  updateData ,
493+             uint  updateFee 
494+         ) =  createBatchedTwapUpdateDataFromMessages (messages);
495+ 
496+         vm.expectRevert (PythErrors.InvalidTwapUpdateDataSet.selector );
497+         pyth.parseTwapPriceFeedUpdates {value: updateFee}(updateData, priceIds);
498+     }
499+ 
500+     function testParseTwapPriceFeedUpdatesRevertsWithInvalidTimeOrdering  ()
501+         public 
502+     {
503+         bytes32 [] memory  priceIds =  new  bytes32 [](1 );
504+         priceIds[0 ] =  bytes32 (uint256 (1 ));
505+ 
506+         PriceFeedMessage[] memory  messages =  new  PriceFeedMessage [](2 );
507+ 
508+         // Start message with later time 
509+         messages[0 ].priceId =  priceIds[0 ];
510+         messages[0 ].price =  100 ;
511+         messages[0 ].publishTime =  1100 ; // Later time 
512+         messages[0 ].prevPublishTime =  1000 ;
513+ 
514+         // End message with earlier time 
515+         messages[1 ].priceId =  priceIds[0 ];
516+         messages[1 ].price =  110 ;
517+         messages[1 ].publishTime =  1000 ; // Earlier time 
518+         messages[1 ].prevPublishTime =  900 ;
519+ 
520+         (
521+             bytes [][] memory  updateData ,
522+             uint  updateFee 
523+         ) =  createBatchedTwapUpdateDataFromMessages (messages);
524+ 
525+         vm.expectRevert (PythErrors.InvalidTwapUpdateDataSet.selector );
526+         pyth.parseTwapPriceFeedUpdates {value: updateFee}(updateData, priceIds);
527+     }
528+ 
529+     function testParseTwapPriceFeedUpdatesRevertsWithMismatchedExponents  ()
530+         public 
531+     {
532+         bytes32 [] memory  priceIds =  new  bytes32 [](1 );
533+         priceIds[0 ] =  bytes32 (uint256 (1 ));
534+ 
535+         PriceFeedMessage[] memory  messages =  new  PriceFeedMessage [](2 );
536+ 
537+         // Start message with expo -8 
538+         messages[0 ].priceId =  priceIds[0 ];
539+         messages[0 ].price =  100 ;
540+         messages[0 ].expo =  - 8 ;
541+         messages[0 ].publishTime =  1000 ;
542+         messages[0 ].prevPublishTime =  900 ;
543+ 
544+         // End message with different expo -6 
545+         messages[1 ].priceId =  priceIds[0 ];
546+         messages[1 ].price =  110 ;
547+         messages[1 ].expo =  - 6 ; // Different exponent 
548+         messages[1 ].publishTime =  1100 ;
549+         messages[1 ].prevPublishTime =  1000 ;
550+ 
551+         (
552+             bytes [][] memory  updateData ,
553+             uint  updateFee 
554+         ) =  createBatchedTwapUpdateDataFromMessages (messages);
555+ 
556+         vm.expectRevert (PythErrors.InvalidTwapUpdateDataSet.selector );
557+         pyth.parseTwapPriceFeedUpdates {value: updateFee}(updateData, priceIds);
558+     }
559+ 
560+     function testParseTwapPriceFeedUpdatesRevertsWithInvalidPrevPublishTime  ()
561+         public 
562+     {
563+         bytes32 [] memory  priceIds =  new  bytes32 [](1 );
564+         priceIds[0 ] =  bytes32 (uint256 (1 ));
565+ 
566+         PriceFeedMessage[] memory  messages =  new  PriceFeedMessage [](2 );
567+ 
568+         // Start message with invalid prevPublishTime 
569+         messages[0 ].priceId =  priceIds[0 ];
570+         messages[0 ].price =  100 ;
571+         messages[0 ].publishTime =  1000 ;
572+         messages[0 ].prevPublishTime =  1100 ; // Invalid: prevPublishTime > publishTime 
573+ 
574+         // End message 
575+         messages[1 ].priceId =  priceIds[0 ];
576+         messages[1 ].price =  110 ;
577+         messages[1 ].publishTime =  1200 ;
578+         messages[1 ].prevPublishTime =  1000 ;
579+ 
580+         (
581+             bytes [][] memory  updateData ,
582+             uint  updateFee 
583+         ) =  createBatchedTwapUpdateDataFromMessages (messages);
584+ 
585+         vm.expectRevert (PythErrors.InvalidTwapUpdateData.selector );
586+         pyth.parseTwapPriceFeedUpdates {value: updateFee}(updateData, priceIds);
587+     }
588+ 
589+     function testParseTwapPriceFeedUpdatesRevertsWithInsufficientFee  () public  {
590+         bytes32 [] memory  priceIds =  new  bytes32 [](1 );
591+         priceIds[0 ] =  bytes32 (uint256 (1 ));
592+ 
593+         PriceFeedMessage[] memory  messages =  new  PriceFeedMessage [](2 );
594+ 
595+         messages[0 ].priceId =  priceIds[0 ];
596+         messages[0 ].price =  100 ;
597+         messages[0 ].publishTime =  1000 ;
598+         messages[0 ].prevPublishTime =  900 ;
599+ 
600+         messages[1 ].priceId =  priceIds[0 ];
601+         messages[1 ].price =  110 ;
602+         messages[1 ].publishTime =  1100 ;
603+         messages[1 ].prevPublishTime =  1000 ;
604+ 
605+         (
606+             bytes [][] memory  updateData ,
607+             uint  updateFee 
608+         ) =  createBatchedTwapUpdateDataFromMessages (messages);
609+ 
610+         vm.expectRevert (PythErrors.InsufficientFee.selector );
611+         pyth.parseTwapPriceFeedUpdates {value: updateFee -  1 }(
612+             updateData,
613+             priceIds
614+         ); // Send insufficient fee 
615+     }
454616}
0 commit comments