1use alloc::string::ToString;
2use core::cmp::Ordering;
3use core::fmt::{self, Write};
4use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign};
5use core::str::FromStr;
6use serde::{de, ser, Deserialize, Deserializer, Serialize};
7
8use crate::errors::{
9 CheckedFromRatioError, CheckedMultiplyRatioError, DivideByZeroError, ErrorKind, OverflowError,
10 OverflowOperation, RoundUpOverflowError, StdError,
11};
12use crate::forward_ref::{forward_ref_binop, forward_ref_op_assign};
13use crate::{Decimal256, SignedDecimal, SignedDecimal256, __internal::forward_ref_partial_eq};
14
15use super::Fraction;
16use super::Isqrt;
17use super::{Uint128, Uint256};
18
19#[derive(
23 Copy,
24 Clone,
25 Default,
26 PartialEq,
27 Eq,
28 PartialOrd,
29 Ord,
30 schemars::JsonSchema,
31 cw_schema::Schemaifier,
32)]
33#[schemaifier(type = cw_schema::NodeType::Decimal { precision: 128, signed: false })]
34pub struct Decimal(#[schemars(with = "String")] Uint128);
35
36forward_ref_partial_eq!(Decimal, Decimal);
37
38#[derive(Debug, PartialEq, Eq, thiserror::Error)]
39#[error("Decimal range exceeded")]
40pub struct DecimalRangeExceeded;
41
42impl Decimal {
43 const DECIMAL_FRACTIONAL: Uint128 = Uint128::new(1_000_000_000_000_000_000u128); const DECIMAL_FRACTIONAL_SQUARED: Uint128 =
45 Uint128::new(1_000_000_000_000_000_000_000_000_000_000_000_000u128); pub const DECIMAL_PLACES: u32 = 18; pub const MAX: Self = Self(Uint128::MAX);
52 pub const MIN: Self = Self(Uint128::MIN);
54
55 #[inline]
67 #[must_use]
68 pub const fn new(value: Uint128) -> Self {
69 Self(value)
70 }
71
72 #[deprecated(
75 since = "3.0.0",
76 note = "Use Decimal::new(Uint128::new(value)) instead"
77 )]
78 pub const fn raw(value: u128) -> Self {
79 Self(Uint128::new(value))
80 }
81
82 #[inline]
84 pub const fn one() -> Self {
85 Self(Self::DECIMAL_FRACTIONAL)
86 }
87
88 #[inline]
90 pub const fn zero() -> Self {
91 Self(Uint128::zero())
92 }
93
94 pub const fn percent(x: u64) -> Self {
106 let atomics = (x as u128) * 10_000_000_000_000_000;
108 Self(Uint128::new(atomics))
109 }
110
111 pub const fn permille(x: u64) -> Self {
123 let atomics = (x as u128) * 1_000_000_000_000_000;
125 Self(Uint128::new(atomics))
126 }
127
128 pub const fn bps(x: u64) -> Self {
142 let atomics = (x as u128) * 100_000_000_000_000;
144 Self(Uint128::new(atomics))
145 }
146
147 pub fn from_atomics(
169 atomics: impl Into<Uint128>,
170 decimal_places: u32,
171 ) -> Result<Self, DecimalRangeExceeded> {
172 let atomics = atomics.into();
173 const TEN: Uint128 = Uint128::new(10);
174 Ok(match decimal_places.cmp(&Self::DECIMAL_PLACES) {
175 Ordering::Less => {
176 let digits = (Self::DECIMAL_PLACES) - decimal_places; let factor = TEN.checked_pow(digits).unwrap(); Self(
179 atomics
180 .checked_mul(factor)
181 .map_err(|_| DecimalRangeExceeded)?,
182 )
183 }
184 Ordering::Equal => Self(atomics),
185 Ordering::Greater => {
186 let digits = decimal_places - (Self::DECIMAL_PLACES); if atomics.is_zero() || digits > atomics.ilog10() {
188 Self(Uint128::zero())
190 } else {
191 let factor = TEN.checked_pow(digits).unwrap();
193 Self(atomics.checked_div(factor).unwrap()) }
195 }
196 })
197 }
198
199 pub fn from_ratio(numerator: impl Into<Uint128>, denominator: impl Into<Uint128>) -> Self {
201 match Decimal::checked_from_ratio(numerator, denominator) {
202 Ok(value) => value,
203 Err(CheckedFromRatioError::DivideByZero) => {
204 panic!("Denominator must not be zero")
205 }
206 Err(CheckedFromRatioError::Overflow) => panic!("Multiplication overflow"),
207 }
208 }
209
210 pub fn checked_from_ratio(
212 numerator: impl Into<Uint128>,
213 denominator: impl Into<Uint128>,
214 ) -> Result<Self, CheckedFromRatioError> {
215 let numerator: Uint128 = numerator.into();
216 let denominator: Uint128 = denominator.into();
217 match numerator.checked_multiply_ratio(Self::DECIMAL_FRACTIONAL, denominator) {
218 Ok(ratio) => {
219 Ok(Decimal(ratio))
221 }
222 Err(CheckedMultiplyRatioError::Overflow) => Err(CheckedFromRatioError::Overflow),
223 Err(CheckedMultiplyRatioError::DivideByZero) => {
224 Err(CheckedFromRatioError::DivideByZero)
225 }
226 }
227 }
228
229 #[must_use]
230 pub const fn is_zero(&self) -> bool {
231 self.0.is_zero()
232 }
233
234 #[must_use]
253 #[inline]
254 pub const fn atomics(&self) -> Uint128 {
255 self.0
256 }
257
258 #[must_use]
263 #[inline]
264 pub const fn decimal_places(&self) -> u32 {
265 Self::DECIMAL_PLACES
266 }
267
268 #[must_use = "this returns the result of the operation, without modifying the original"]
270 pub fn floor(&self) -> Self {
271 Self((self.0 / Self::DECIMAL_FRACTIONAL) * Self::DECIMAL_FRACTIONAL)
272 }
273
274 #[must_use = "this returns the result of the operation, without modifying the original"]
276 pub fn ceil(&self) -> Self {
277 match self.checked_ceil() {
278 Ok(value) => value,
279 Err(_) => panic!("attempt to ceil with overflow"),
280 }
281 }
282
283 pub fn checked_ceil(&self) -> Result<Self, RoundUpOverflowError> {
285 let floor = self.floor();
286 if floor == self {
287 Ok(floor)
288 } else {
289 floor
290 .checked_add(Decimal::one())
291 .map_err(|_| RoundUpOverflowError)
292 }
293 }
294
295 pub fn checked_add(self, other: Self) -> Result<Self, OverflowError> {
296 self.0
297 .checked_add(other.0)
298 .map(Self)
299 .map_err(|_| OverflowError::new(OverflowOperation::Add))
300 }
301
302 pub fn checked_sub(self, other: Self) -> Result<Self, OverflowError> {
303 self.0
304 .checked_sub(other.0)
305 .map(Self)
306 .map_err(|_| OverflowError::new(OverflowOperation::Sub))
307 }
308
309 pub fn checked_mul(self, other: Self) -> Result<Self, OverflowError> {
311 let result_as_uint256 = self.numerator().full_mul(other.numerator())
312 / Uint256::from_uint128(Self::DECIMAL_FRACTIONAL); result_as_uint256
314 .try_into()
315 .map(Self)
316 .map_err(|_| OverflowError::new(OverflowOperation::Mul))
317 }
318
319 #[must_use = "this returns the result of the operation, without modifying the original"]
321 pub fn pow(self, exp: u32) -> Self {
322 match self.checked_pow(exp) {
323 Ok(value) => value,
324 Err(_) => panic!("Multiplication overflow"),
325 }
326 }
327
328 pub fn checked_pow(self, exp: u32) -> Result<Self, OverflowError> {
330 fn inner(mut x: Decimal, mut n: u32) -> Result<Decimal, OverflowError> {
334 if n == 0 {
335 return Ok(Decimal::one());
336 }
337
338 let mut y = Decimal::one();
339
340 while n > 1 {
341 if n % 2 == 0 {
342 x = x.checked_mul(x)?;
343 n /= 2;
344 } else {
345 y = x.checked_mul(y)?;
346 x = x.checked_mul(x)?;
347 n = (n - 1) / 2;
348 }
349 }
350
351 Ok(x * y)
352 }
353
354 inner(self, exp).map_err(|_| OverflowError::new(OverflowOperation::Pow))
355 }
356
357 pub fn checked_div(self, other: Self) -> Result<Self, CheckedFromRatioError> {
358 Decimal::checked_from_ratio(self.numerator(), other.numerator())
359 }
360
361 pub fn checked_rem(self, other: Self) -> Result<Self, DivideByZeroError> {
362 self.0
363 .checked_rem(other.0)
364 .map(Self)
365 .map_err(|_| DivideByZeroError)
366 }
367
368 #[must_use = "this returns the result of the operation, without modifying the original"]
372 pub fn sqrt(&self) -> Self {
373 if self.0.is_zero() {
376 return self.sqrt_with_precision(Self::DECIMAL_PLACES / 2).unwrap();
378 }
379
380 let precision_guess = (38 - self.0.ilog10()) / 2;
383 let precision = core::cmp::min(precision_guess, Self::DECIMAL_PLACES / 2);
384
385 self.sqrt_with_precision(precision)
389 .or_else(|| self.sqrt_with_precision(precision - 1))
390 .unwrap()
391 }
392
393 #[must_use = "this returns the result of the operation, without modifying the original"]
398 fn sqrt_with_precision(&self, precision: u32) -> Option<Self> {
399 let inner_mul = 100u128.pow(precision);
400 self.0.checked_mul(inner_mul.into()).ok().map(|inner| {
401 let outer_mul = Uint128::from(10u128).pow(Self::DECIMAL_PLACES / 2 - precision);
402 Decimal(inner.isqrt().checked_mul(outer_mul).unwrap())
403 })
404 }
405
406 #[must_use = "this returns the result of the operation, without modifying the original"]
407 pub const fn abs_diff(self, other: Self) -> Self {
408 Self(self.0.abs_diff(other.0))
409 }
410
411 #[must_use = "this returns the result of the operation, without modifying the original"]
412 pub fn saturating_add(self, other: Self) -> Self {
413 self.checked_add(other).unwrap_or(Self::MAX)
414 }
415
416 #[must_use = "this returns the result of the operation, without modifying the original"]
417 pub fn saturating_sub(self, other: Self) -> Self {
418 self.checked_sub(other).unwrap_or_else(|_| Self::zero())
419 }
420
421 #[must_use = "this returns the result of the operation, without modifying the original"]
422 pub fn saturating_mul(self, other: Self) -> Self {
423 self.checked_mul(other).unwrap_or(Self::MAX)
424 }
425
426 #[must_use = "this returns the result of the operation, without modifying the original"]
427 pub fn saturating_pow(self, exp: u32) -> Self {
428 self.checked_pow(exp).unwrap_or(Self::MAX)
429 }
430
431 #[must_use = "this returns the result of the operation, without modifying the original"]
450 pub fn to_uint_floor(self) -> Uint128 {
451 self.0 / Self::DECIMAL_FRACTIONAL
452 }
453
454 #[must_use = "this returns the result of the operation, without modifying the original"]
473 pub fn to_uint_ceil(self) -> Uint128 {
474 let x = self.0;
477 let y = Self::DECIMAL_FRACTIONAL;
478 if x.is_zero() {
479 Uint128::zero()
480 } else {
481 Uint128::one() + ((x - Uint128::one()) / y)
482 }
483 }
484}
485
486impl Fraction<Uint128> for Decimal {
487 #[inline]
488 fn numerator(&self) -> Uint128 {
489 self.0
490 }
491
492 #[inline]
493 fn denominator(&self) -> Uint128 {
494 Self::DECIMAL_FRACTIONAL
495 }
496
497 fn inv(&self) -> Option<Self> {
501 if self.is_zero() {
502 None
503 } else {
504 Some(Decimal(Self::DECIMAL_FRACTIONAL_SQUARED / self.0))
508 }
509 }
510}
511
512impl TryFrom<Decimal256> for Decimal {
513 type Error = DecimalRangeExceeded;
514
515 fn try_from(value: Decimal256) -> Result<Self, Self::Error> {
516 value
517 .atomics()
518 .try_into()
519 .map(Decimal)
520 .map_err(|_| DecimalRangeExceeded)
521 }
522}
523
524impl TryFrom<SignedDecimal> for Decimal {
525 type Error = DecimalRangeExceeded;
526
527 fn try_from(value: SignedDecimal) -> Result<Self, Self::Error> {
528 value
529 .atomics()
530 .try_into()
531 .map(Decimal)
532 .map_err(|_| DecimalRangeExceeded)
533 }
534}
535
536impl TryFrom<SignedDecimal256> for Decimal {
537 type Error = DecimalRangeExceeded;
538
539 fn try_from(value: SignedDecimal256) -> Result<Self, Self::Error> {
540 value
541 .atomics()
542 .try_into()
543 .map(Decimal)
544 .map_err(|_| DecimalRangeExceeded)
545 }
546}
547
548impl TryFrom<Uint128> for Decimal {
549 type Error = DecimalRangeExceeded;
550
551 #[inline]
552 fn try_from(value: Uint128) -> Result<Self, Self::Error> {
553 Self::from_atomics(value, 0)
554 }
555}
556
557impl FromStr for Decimal {
558 type Err = StdError;
559
560 fn from_str(input: &str) -> Result<Self, Self::Err> {
567 let mut parts_iter = input.split('.');
568
569 let whole_part = parts_iter.next().unwrap(); let whole = whole_part.parse::<Uint128>()?;
571 let mut atomics = whole.checked_mul(Self::DECIMAL_FRACTIONAL)?;
572
573 if let Some(fractional_part) = parts_iter.next() {
574 let fractional = fractional_part.parse::<Uint128>()?;
575 let exp = Self::DECIMAL_PLACES
576 .checked_sub(fractional_part.len() as u32)
577 .ok_or_else(|| {
578 StdError::msg(format_args!(
579 "Cannot parse more than {} fractional digits",
580 Self::DECIMAL_PLACES
581 ))
582 })?;
583 debug_assert!(exp <= Self::DECIMAL_PLACES);
584 let fractional_factor = Uint128::from(10u128.pow(exp));
585 atomics = atomics.checked_add(
586 fractional.checked_mul(fractional_factor).unwrap(),
589 )?;
590 }
591
592 if parts_iter.next().is_some() {
593 return Err(StdError::msg("Unexpected number of dots").with_kind(ErrorKind::Parsing));
594 }
595
596 Ok(Decimal(atomics))
597 }
598}
599
600impl fmt::Display for Decimal {
601 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
602 let whole = (self.0) / Self::DECIMAL_FRACTIONAL;
603 let fractional = self.0.checked_rem(Self::DECIMAL_FRACTIONAL).unwrap();
604
605 if fractional.is_zero() {
606 write!(f, "{whole}")
607 } else {
608 let fractional_string = format!(
609 "{:0>padding$}",
610 fractional,
611 padding = Self::DECIMAL_PLACES as usize
612 );
613 f.write_str(&whole.to_string())?;
614 f.write_char('.')?;
615 f.write_str(fractional_string.trim_end_matches('0'))?;
616 Ok(())
617 }
618 }
619}
620
621impl fmt::Debug for Decimal {
622 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
623 write!(f, "Decimal({self})")
624 }
625}
626
627impl Add for Decimal {
628 type Output = Self;
629
630 fn add(self, other: Self) -> Self {
631 Decimal(self.0 + other.0)
632 }
633}
634forward_ref_binop!(impl Add, add for Decimal, Decimal);
635
636impl AddAssign for Decimal {
637 fn add_assign(&mut self, rhs: Decimal) {
638 *self = *self + rhs;
639 }
640}
641forward_ref_op_assign!(impl AddAssign, add_assign for Decimal, Decimal);
642
643impl Sub for Decimal {
644 type Output = Self;
645
646 fn sub(self, other: Self) -> Self {
647 Decimal(self.0 - other.0)
648 }
649}
650forward_ref_binop!(impl Sub, sub for Decimal, Decimal);
651
652impl SubAssign for Decimal {
653 fn sub_assign(&mut self, rhs: Decimal) {
654 *self = *self - rhs;
655 }
656}
657forward_ref_op_assign!(impl SubAssign, sub_assign for Decimal, Decimal);
658
659impl Mul for Decimal {
660 type Output = Self;
661
662 #[allow(clippy::suspicious_arithmetic_impl)]
663 fn mul(self, other: Self) -> Self {
664 let result_as_uint256 = self.numerator().full_mul(other.numerator())
670 / Uint256::from_uint128(Self::DECIMAL_FRACTIONAL); match result_as_uint256.try_into() {
672 Ok(result) => Self(result),
673 Err(_) => panic!("attempt to multiply with overflow"),
674 }
675 }
676}
677forward_ref_binop!(impl Mul, mul for Decimal, Decimal);
678
679impl MulAssign for Decimal {
680 fn mul_assign(&mut self, rhs: Decimal) {
681 *self = *self * rhs;
682 }
683}
684forward_ref_op_assign!(impl MulAssign, mul_assign for Decimal, Decimal);
685
686impl Div for Decimal {
687 type Output = Self;
688
689 fn div(self, other: Self) -> Self {
690 match Decimal::checked_from_ratio(self.numerator(), other.numerator()) {
691 Ok(ratio) => ratio,
692 Err(CheckedFromRatioError::DivideByZero) => {
693 panic!("Division failed - denominator must not be zero")
694 }
695 Err(CheckedFromRatioError::Overflow) => {
696 panic!("Division failed - multiplication overflow")
697 }
698 }
699 }
700}
701forward_ref_binop!(impl Div, div for Decimal, Decimal);
702
703impl DivAssign for Decimal {
704 fn div_assign(&mut self, rhs: Decimal) {
705 *self = *self / rhs;
706 }
707}
708forward_ref_op_assign!(impl DivAssign, div_assign for Decimal, Decimal);
709
710impl Div<Uint128> for Decimal {
711 type Output = Self;
712
713 fn div(self, rhs: Uint128) -> Self::Output {
714 Decimal(self.0 / rhs)
715 }
716}
717
718impl DivAssign<Uint128> for Decimal {
719 fn div_assign(&mut self, rhs: Uint128) {
720 self.0 /= rhs;
721 }
722}
723
724impl Rem for Decimal {
725 type Output = Self;
726
727 #[inline]
731 fn rem(self, rhs: Self) -> Self {
732 Self(self.0.rem(rhs.0))
733 }
734}
735forward_ref_binop!(impl Rem, rem for Decimal, Decimal);
736
737impl RemAssign<Decimal> for Decimal {
738 fn rem_assign(&mut self, rhs: Decimal) {
739 *self = *self % rhs;
740 }
741}
742forward_ref_op_assign!(impl RemAssign, rem_assign for Decimal, Decimal);
743
744impl<A> core::iter::Sum<A> for Decimal
745where
746 Self: Add<A, Output = Self>,
747{
748 fn sum<I: Iterator<Item = A>>(iter: I) -> Self {
749 iter.fold(Self::zero(), Add::add)
750 }
751}
752
753impl Serialize for Decimal {
755 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
756 where
757 S: ser::Serializer,
758 {
759 serializer.serialize_str(&self.to_string())
760 }
761}
762
763impl<'de> Deserialize<'de> for Decimal {
765 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
766 where
767 D: Deserializer<'de>,
768 {
769 deserializer.deserialize_str(DecimalVisitor)
770 }
771}
772
773struct DecimalVisitor;
774
775impl de::Visitor<'_> for DecimalVisitor {
776 type Value = Decimal;
777
778 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
779 formatter.write_str("expected string-encoded decimal")
780 }
781
782 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
783 where
784 E: de::Error,
785 {
786 match Decimal::from_str(v) {
787 Ok(d) => Ok(d),
788 Err(e) => Err(E::custom(format_args!("Error parsing decimal '{v}': {e}"))),
789 }
790 }
791}