@@ -16,6 +16,7 @@ use pyth_sdk::{
16
16
PriceIdentifier ,
17
17
UnixTimestamp ,
18
18
} ;
19
+ use solana_program:: clock:: Clock ;
19
20
use solana_program:: pubkey:: Pubkey ;
20
21
use std:: mem:: size_of;
21
22
@@ -354,6 +355,32 @@ impl PriceAccount {
354
355
}
355
356
}
356
357
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
+
357
384
pub fn to_price_feed ( & self , price_key : & Pubkey ) -> PriceFeed {
358
385
let status = self . agg . status ;
359
386
@@ -480,6 +507,7 @@ mod test {
480
507
Price ,
481
508
PriceFeed ,
482
509
} ;
510
+ use solana_program:: clock:: Clock ;
483
511
use solana_program:: pubkey:: Pubkey ;
484
512
485
513
use super :: {
@@ -585,4 +613,128 @@ mod test {
585
613
)
586
614
) ;
587
615
}
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
+ }
588
740
}
0 commit comments