ve3_shared/helpers/
bps.rs1use cosmwasm_schema::cw_serde;
2use cosmwasm_std::{Decimal, Fraction, StdError, Uint128};
3use std::convert::{TryFrom, TryInto};
4use std::ops::Mul;
5
6#[cw_serde]
11#[derive(Default, Copy)]
12pub struct BasicPoints(u16);
13
14impl BasicPoints {
15 pub const MAX: u16 = 10000;
16
17 pub fn checked_add(self, rhs: Self) -> Result<Self, StdError> {
18 let next_value = self.0 + rhs.0;
19 if next_value > Self::MAX {
20 Err(StdError::generic_err("Basic points sum exceeds limit"))
21 } else {
22 Ok(Self(next_value))
23 }
24 }
25
26 pub fn from_ratio(numerator: Uint128, denominator: Uint128) -> Result<Self, StdError> {
27 numerator
28 .checked_multiply_ratio(Self::MAX, denominator)
29 .map_err(|_| StdError::generic_err("Checked multiply ratio error!"))?
30 .u128()
31 .try_into()
32 }
33
34 pub fn percent(percent: u16) -> BasicPoints {
35 BasicPoints(percent * 100)
36 }
37
38 pub fn reverse(self) -> BasicPoints {
39 BasicPoints(Self::MAX - self.0)
40 }
41
42 pub fn decimal(self) -> Decimal {
43 Decimal::from_ratio(self.0, Self::MAX)
44 }
45
46 pub fn div_decimal(self, rhs: Self) -> Decimal {
47 if self.is_zero() {
48 return Decimal::zero();
49 }
50 Decimal::from_ratio(self.0, rhs.0)
51 }
52
53 #[inline]
54 pub const fn max() -> Self {
55 BasicPoints(BasicPoints::MAX)
56 }
57
58 #[inline]
59 pub const fn one() -> Self {
60 BasicPoints(BasicPoints::MAX)
61 }
62
63 #[inline]
64 pub const fn zero() -> Self {
65 BasicPoints(0)
66 }
67
68 pub const fn u16(self) -> u16 {
69 self.0
70 }
71
72 pub const fn is_max(self) -> bool {
73 self.0 == BasicPoints::MAX
74 }
75 pub const fn is_zero(self) -> bool {
76 self.0 == 0
77 }
78}
79
80impl TryFrom<u16> for BasicPoints {
81 type Error = StdError;
82
83 fn try_from(value: u16) -> Result<Self, Self::Error> {
84 if value <= Self::MAX {
85 Ok(Self(value))
86 } else {
87 Err(StdError::generic_err(format!("Basic points conversion error. {0} > 10000", value)))
88 }
89 }
90}
91
92impl TryFrom<u128> for BasicPoints {
93 type Error = StdError;
94
95 fn try_from(value: u128) -> Result<Self, Self::Error> {
96 if value <= Self::MAX as u128 {
97 Ok(Self(value as u16))
98 } else {
99 Err(StdError::generic_err(format!("Basic points conversion error. {0} > 10000", value)))
100 }
101 }
102}
103
104impl TryFrom<Decimal> for BasicPoints {
105 type Error = StdError;
106
107 fn try_from(value: Decimal) -> Result<Self, Self::Error> {
108 if value > Decimal::one() {
109 Err(StdError::generic_err(format!("Basic points conversion error. {0} > 10000", value)))
110 } else {
111 BasicPoints::from_ratio(value.numerator(), value.denominator())
112 }
113 }
114}
115
116impl From<BasicPoints> for u16 {
117 fn from(value: BasicPoints) -> Self {
118 value.0
119 }
120}
121
122impl From<BasicPoints> for Uint128 {
123 fn from(value: BasicPoints) -> Self {
124 Uint128::from(u16::from(value))
125 }
126}
127
128impl Mul<Uint128> for BasicPoints {
129 type Output = Uint128;
130
131 fn mul(self, rhs: Uint128) -> Self::Output {
132 if self.is_max() {
133 rhs
134 } else {
135 rhs.multiply_ratio(self.0, Self::MAX)
136 }
137 }
138}
139
140impl Mul<Decimal> for BasicPoints {
141 type Output = Decimal;
142
143 fn mul(self, rhs: Decimal) -> Self::Output {
144 Decimal::from_ratio(
145 rhs.numerator() * Uint128::from(self.0),
146 rhs.denominator() * Uint128::from(Self::MAX),
147 )
148 }
149}