@@ -16,6 +16,7 @@ use pyth_sdk::{
1616 PriceIdentifier ,
1717 UnixTimestamp ,
1818} ;
19+ use solana_program:: clock:: Clock ;
1920use solana_program:: pubkey:: Pubkey ;
2021use std:: mem:: size_of;
2122
@@ -354,6 +355,32 @@ impl PriceAccount {
354355 }
355356 }
356357
358+ /// Get the last valid price as long as it was updated within `slot_threshold` slots of the
359+ /// current slot.
360+ pub fn get_price_no_older_than ( & self , clock : & Clock , slot_threshold : u64 ) -> Option < Price > {
361+ if self . agg . status == PriceStatus :: Trading
362+ && self . agg . pub_slot >= clock. slot - slot_threshold
363+ {
364+ return Some ( Price {
365+ conf : self . agg . conf ,
366+ expo : self . expo ,
367+ price : self . agg . price ,
368+ publish_time : self . timestamp ,
369+ } ) ;
370+ }
371+
372+ if self . prev_slot >= clock. slot - slot_threshold {
373+ return Some ( Price {
374+ conf : self . prev_conf ,
375+ expo : self . expo ,
376+ price : self . prev_price ,
377+ publish_time : self . prev_timestamp ,
378+ } ) ;
379+ }
380+
381+ None
382+ }
383+
357384 pub fn to_price_feed ( & self , price_key : & Pubkey ) -> PriceFeed {
358385 let status = self . agg . status ;
359386
@@ -480,6 +507,7 @@ mod test {
480507 Price ,
481508 PriceFeed ,
482509 } ;
510+ use solana_program:: clock:: Clock ;
483511 use solana_program:: pubkey:: Pubkey ;
484512
485513 use super :: {
@@ -585,4 +613,128 @@ mod test {
585613 )
586614 ) ;
587615 }
616+
617+ #[ test]
618+ fn test_happy_use_latest_price_in_price_no_older_than ( ) {
619+ let price_account = PriceAccount {
620+ expo : 5 ,
621+ agg : PriceInfo {
622+ price : 10 ,
623+ conf : 20 ,
624+ status : PriceStatus :: Trading ,
625+ pub_slot : 1 ,
626+ ..Default :: default ( )
627+ } ,
628+ timestamp : 200 ,
629+ prev_timestamp : 100 ,
630+ prev_price : 60 ,
631+ prev_conf : 70 ,
632+ ..Default :: default ( )
633+ } ;
634+
635+ let clock = Clock {
636+ slot : 5 ,
637+ ..Default :: default ( )
638+ } ;
639+
640+ assert_eq ! (
641+ price_account. get_price_no_older_than( & clock, 4 ) ,
642+ Some ( Price {
643+ conf: 20 ,
644+ expo: 5 ,
645+ price: 10 ,
646+ publish_time: 200 ,
647+ } )
648+ ) ;
649+ }
650+
651+ #[ test]
652+ fn test_happy_use_prev_price_in_price_no_older_than ( ) {
653+ let price_account = PriceAccount {
654+ expo : 5 ,
655+ agg : PriceInfo {
656+ price : 10 ,
657+ conf : 20 ,
658+ status : PriceStatus :: Unknown ,
659+ pub_slot : 3 ,
660+ ..Default :: default ( )
661+ } ,
662+ timestamp : 200 ,
663+ prev_timestamp : 100 ,
664+ prev_price : 60 ,
665+ prev_conf : 70 ,
666+ prev_slot : 1 ,
667+ ..Default :: default ( )
668+ } ;
669+
670+ let clock = Clock {
671+ slot : 5 ,
672+ ..Default :: default ( )
673+ } ;
674+
675+ assert_eq ! (
676+ price_account. get_price_no_older_than( & clock, 4 ) ,
677+ Some ( Price {
678+ conf: 70 ,
679+ expo: 5 ,
680+ price: 60 ,
681+ publish_time: 100 ,
682+ } )
683+ ) ;
684+ }
685+
686+ #[ test]
687+ fn test_sad_cur_price_unknown_in_price_no_older_than ( ) {
688+ let price_account = PriceAccount {
689+ expo : 5 ,
690+ agg : PriceInfo {
691+ price : 10 ,
692+ conf : 20 ,
693+ status : PriceStatus :: Unknown ,
694+ pub_slot : 3 ,
695+ ..Default :: default ( )
696+ } ,
697+ timestamp : 200 ,
698+ prev_timestamp : 100 ,
699+ prev_price : 60 ,
700+ prev_conf : 70 ,
701+ prev_slot : 1 ,
702+ ..Default :: default ( )
703+ } ;
704+
705+ let clock = Clock {
706+ slot : 5 ,
707+ ..Default :: default ( )
708+ } ;
709+
710+ // current price is unknown, prev price is too stale
711+ assert_eq ! ( price_account. get_price_no_older_than( & clock, 3 ) , None ) ;
712+ }
713+
714+ #[ test]
715+ fn test_sad_cur_price_stale_in_price_no_older_than ( ) {
716+ let price_account = PriceAccount {
717+ expo : 5 ,
718+ agg : PriceInfo {
719+ price : 10 ,
720+ conf : 20 ,
721+ status : PriceStatus :: Trading ,
722+ pub_slot : 3 ,
723+ ..Default :: default ( )
724+ } ,
725+ timestamp : 200 ,
726+ prev_timestamp : 100 ,
727+ prev_price : 60 ,
728+ prev_conf : 70 ,
729+ prev_slot : 1 ,
730+ ..Default :: default ( )
731+ } ;
732+
733+ let clock = Clock {
734+ slot : 5 ,
735+ ..Default :: default ( )
736+ } ;
737+
738+ assert_eq ! ( price_account. get_price_no_older_than( & clock, 1 ) , None ) ;
739+ }
588740}
0 commit comments