templar_proxy_oracle_kernel/
price.rs1#[cfg(feature = "schemars")]
2use alloc::borrow::ToOwned;
3#[cfg(any(feature = "borsh", feature = "schemars"))]
4use alloc::string::ToString;
5use core::cmp::Ordering;
6
7use templar_primitives::time::Nanoseconds;
8
9serialize! {
10 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
11 pub struct Price {
12 pub price: i64,
13 pub conf: u64,
15 pub expo: i32,
17 pub publish_time_ns: Nanoseconds,
19 }
20}
21
22impl Price {
23 #[must_use]
24 pub fn has_strictly_positive_confidence_interval(&self) -> bool {
25 u64::try_from(self.price).is_ok_and(|price| price > self.conf)
26 }
27}
28
29pub(crate) fn compare_scaled(
33 left_value: i64,
34 left_exponent: i32,
35 right_value: i64,
36 right_exponent: i32,
37) -> Ordering {
38 match (left_value.cmp(&0), right_value.cmp(&0)) {
39 (Ordering::Equal, right_sign) => return right_sign.reverse(),
40 (left_sign, Ordering::Equal) => return left_sign,
41 (left_sign, right_sign) if left_sign != right_sign => return left_sign,
42 _ => {}
43 }
44
45 let negative = left_value.is_negative();
46 let left_abs = u128::from(left_value.unsigned_abs());
47 let right_abs = u128::from(right_value.unsigned_abs());
48 let left_log10 = left_abs.ilog10();
49 let right_log10 = right_abs.ilog10();
50
51 let left_scale = i64::from(left_exponent) + i64::from(left_log10);
52 let right_scale = i64::from(right_exponent) + i64::from(right_log10);
53 let magnitude_order = left_scale.cmp(&right_scale).then_with(|| {
54 let max_digits = left_log10.max(right_log10);
55 let left_scaled = left_abs * 10u128.pow(max_digits - left_log10);
56 let right_scaled = right_abs * 10u128.pow(max_digits - right_log10);
57 left_scaled.cmp(&right_scaled)
58 });
59
60 if negative {
61 magnitude_order.reverse()
62 } else {
63 magnitude_order
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use templar_primitives::Nanoseconds;
70
71 use super::*;
72
73 fn price(price: i64, conf: u64) -> Price {
74 Price {
75 price,
76 conf,
77 expo: 0,
78 publish_time_ns: Nanoseconds::zero(),
79 }
80 }
81
82 #[rstest::rstest]
83 #[case(price(1, 0), true)]
84 #[case(price(2, 1), true)]
85 #[case(price(1, 1), false)]
86 #[case(price(1, 2), false)]
87 #[case(price(0, 0), false)]
88 #[case(price(-1, 0), false)]
89 fn validates_strictly_positive_confidence_interval(
90 #[case] price: Price,
91 #[case] expected: bool,
92 ) {
93 assert_eq!(price.has_strictly_positive_confidence_interval(), expected);
94 }
95}