1use std::{
2 cmp::Ordering,
3 ops::{Deref, Div, DivAssign, Mul, MulAssign},
4};
5
6use cosmwasm_schema::cw_serde;
7use cosmwasm_std::{Decimal, Fraction, StdResult, Uint128};
8
9use crate::querier::KujiraQuerier;
10
11pub const REFERENCE_DECIMAL_PLACES: u8 = 6;
12
13#[cw_serde]
20#[derive(Copy, Eq, PartialOrd, Ord)]
21pub struct HumanPrice(Decimal);
22
23impl HumanPrice {
24 pub fn normalize(&self, decimals: u8) -> NormalizedPrice {
25 NormalizedPrice::from_raw(self.0, decimals)
26 }
27}
28
29impl From<Decimal> for HumanPrice {
30 fn from(value: Decimal) -> Self {
31 HumanPrice(value)
32 }
33}
34
35impl From<HumanPrice> for Decimal {
36 fn from(value: HumanPrice) -> Self {
37 value.0
38 }
39}
40
41#[cw_serde]
49#[derive(Copy, Eq, PartialOrd, Ord)]
50pub struct NormalizedPrice(Decimal);
51
52impl NormalizedPrice {
53 pub fn unsafe_unchecked(price: Decimal) -> Self {
57 Self(price)
58 }
59
60 pub fn from_raw(price: Decimal, decimals: u8) -> Self {
61 let delta: i16 = i16::from(REFERENCE_DECIMAL_PLACES) - i16::from(decimals);
63 Self::from_delta(price, delta)
64 }
65
66 pub fn from_delta(price: Decimal, delta: i16) -> Self {
67 match delta.cmp(&0) {
68 Ordering::Equal => Self(price),
69 Ordering::Greater => Self(Decimal::from_ratio(
70 price.numerator() * Uint128::from(10u128.pow(u32::from(delta.unsigned_abs()))),
71 price.denominator(),
72 )),
73 Ordering::Less => Self(Decimal::from_ratio(
74 price.numerator(),
75 price.denominator() * Uint128::from(10u128.pow(u32::from(delta.unsigned_abs()))),
76 )),
77 }
78 }
79
80 pub fn from_oracle<T: Into<String>>(
81 querier: &KujiraQuerier,
82 denom: T,
83 decimals: u8,
84 ) -> StdResult<Self> {
85 querier
86 .query_exchange_rate(denom)
87 .map(|price| price.normalize(decimals))
88 }
89
90 pub fn inner(&self) -> Decimal {
91 self.0
92 }
93}
94
95impl Deref for NormalizedPrice {
96 type Target = Decimal;
97
98 fn deref(&self) -> &Self::Target {
99 &self.0
100 }
101}
102
103impl From<NormalizedPrice> for Decimal {
104 fn from(price: NormalizedPrice) -> Self {
105 price.0
106 }
107}
108
109impl Mul<NormalizedPrice> for NormalizedPrice {
110 type Output = NormalizedPrice;
111
112 fn mul(self, rhs: NormalizedPrice) -> Self::Output {
113 NormalizedPrice(self.0 * rhs.0)
114 }
115}
116
117impl MulAssign<NormalizedPrice> for NormalizedPrice {
118 fn mul_assign(&mut self, rhs: NormalizedPrice) {
119 self.0 *= rhs.0
120 }
121}
122
123impl Div<NormalizedPrice> for NormalizedPrice {
124 type Output = NormalizedPrice;
125
126 fn div(self, rhs: NormalizedPrice) -> Self::Output {
127 NormalizedPrice(self.0 / rhs.0)
128 }
129}
130
131impl DivAssign<NormalizedPrice> for NormalizedPrice {
132 fn div_assign(&mut self, rhs: NormalizedPrice) {
133 self.0 /= rhs.0
134 }
135}
136
137impl Mul<Uint128> for NormalizedPrice {
138 type Output = Uint128;
139
140 fn mul(self, rhs: Uint128) -> Self::Output {
141 rhs.mul_floor(self.0)
142 }
143}
144
145impl Mul<NormalizedPrice> for Uint128 {
146 type Output = Uint128;
147
148 fn mul(self, rhs: NormalizedPrice) -> Self::Output {
149 self.mul_floor(rhs.0)
150 }
151}
152
153impl MulAssign<NormalizedPrice> for Uint128 {
154 fn mul_assign(&mut self, rhs: NormalizedPrice) {
155 *self = self.mul_floor(rhs.0)
156 }
157}
158
159impl Div<Uint128> for NormalizedPrice {
160 type Output = Option<Uint128>;
161
162 fn div(self, rhs: Uint128) -> Self::Output {
163 self.0.inv().map(|inv| rhs.mul_floor(inv))
164 }
165}
166
167impl Div<NormalizedPrice> for Uint128 {
168 type Output = Option<Uint128>;
169
170 fn div(self, rhs: NormalizedPrice) -> Self::Output {
171 rhs.0.inv().map(|inv| self.mul_floor(inv))
172 }
173}
174#[cfg(test)]
175mod tests {
176 use cosmwasm_std::Decimal;
177
178 use super::{HumanPrice, NormalizedPrice};
179
180 #[test]
181 fn serialize_human_price() {
182 let price = HumanPrice(Decimal::percent(459));
183 let serialized = serde_json::to_string(&price).unwrap();
184 assert_eq!(serialized, r#""4.59""#);
185 }
186
187 #[test]
188 fn deserialize_human_price() {
189 let price = HumanPrice(Decimal::percent(459));
190 let deserialized: HumanPrice = serde_json::from_str(r#""4.59""#).unwrap();
191 assert_eq!(price, deserialized);
192 }
193
194 #[test]
195 fn serialize_normalized_price() {
196 let price = NormalizedPrice(Decimal::percent(459));
197 let serialized = serde_json::to_string(&price).unwrap();
198 assert_eq!(serialized, r#""4.59""#);
199 }
200
201 #[test]
202 fn deserialize_normalized_price() {
203 let price = NormalizedPrice(Decimal::percent(459));
204 let deserialized: NormalizedPrice = serde_json::from_str(r#""4.59""#).unwrap();
205 assert_eq!(price, deserialized);
206 }
207}