use core::fmt::{self, Display, Formatter}; use core::ops::{ Add, AddAssign, BitAnd, BitOr, BitXor, Div, DivAssign, Mul, MulAssign, Not, Rem, RemAssign, Shl, Shr, Sub, SubAssign, }; #[cfg(feature = "approx")] use approx::AbsDiffEq; use codec::{ Compact, CompactAs, Decode, DecodeWithMemTracking, Encode, Error as CodecError, MaxEncodedLen, }; use frame_support::pallet_prelude::*; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use substrate_fixed::traits::{Fixed, ToFixed}; use subtensor_macros::freeze_struct; pub use num_traits::{ CheckedShl, CheckedShr, FromPrimitive, Num, NumCast, NumOps, PrimInt, Saturating, Signed, ToPrimitive, Unsigned, checked_pow, }; use sp_arithmetic::per_things::Rounding; use sp_arithmetic::rational::MultiplyRational; use sp_arithmetic::traits::{ Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedSub, One, Zero, }; #[cfg(feature = "std")] use sp_rpc::number::NumberOrHex; #[freeze_struct("fe2aa2d7fcb480e8")] #[repr(transparent)] #[derive( Deserialize, Serialize, Clone, Copy, Decode, DecodeWithMemTracking, Default, Encode, Eq, Hash, MaxEncodedLen, Ord, PartialEq, PartialOrd, RuntimeDebug, TypeInfo, )] pub struct AlphaBalance(u64); #[freeze_struct("a99f2483a97121fc")] #[repr(transparent)] #[derive( Deserialize, Serialize, Clone, Copy, Decode, DecodeWithMemTracking, Default, Encode, Eq, Hash, MaxEncodedLen, Ord, PartialEq, PartialOrd, RuntimeDebug, TypeInfo, )] pub struct TaoBalance(u64); // implements traits required by the Currency trait (ToFixed + Into + From) and CompactAs // and Display. It expects a wrapper structure for u64 (CurrencyT(u64)). // TypeInfo is derived on the structs themselves so the type identity (path) is preserved in the // runtime metadata, letting SDKs generate distinct TaoBalance/AlphaBalance types instead of bare u64. macro_rules! impl_currency_reqs { ($currency_type:ident) => { impl $currency_type { pub const fn new(inner: u64) -> Self { Self(inner) } } impl Display for $currency_type { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { Display::fmt(&self.0, f) } } impl CompactAs for $currency_type { type As = u64; fn encode_as(&self) -> &Self::As { &self.0 } fn decode_from(v: Self::As) -> Result { Ok(Self(v)) } } impl From> for $currency_type { fn from(c: Compact<$currency_type>) -> Self { c.0 } } impl From<$currency_type> for u64 { fn from(val: $currency_type) -> Self { val.0 } } impl From for $currency_type { fn from(value: u64) -> Self { Self(value) } } impl From for $currency_type { fn from(value: u32) -> Self { Self(value as u64) } } // TODO: This is a lossy conversion, maybe it should use try_from impl From for $currency_type { fn from(value: i32) -> Self { Self(value.unsigned_abs().into()) } } impl From for $currency_type { fn from(value: u8) -> Self { Self(value as u64) } } impl ToFixed for $currency_type { fn to_fixed(self) -> F { self.0.to_fixed() } fn checked_to_fixed(self) -> Option { self.0.checked_to_fixed() } fn saturating_to_fixed(self) -> F { self.0.saturating_to_fixed() } fn wrapping_to_fixed(self) -> F { self.0.wrapping_to_fixed() } fn overflowing_to_fixed(self) -> (F, bool) { self.0.overflowing_to_fixed() } } impl Zero for $currency_type { fn zero() -> Self { Self(0) } fn is_zero(&self) -> bool { Into::::into(*self) == 0 } } impl One for $currency_type { fn one() -> Self { Self(1) } } }; } macro_rules! impl_arithmetic_operators { ($currency_type:ident) => { impl Add for $currency_type { type Output = Self; #[allow(clippy::arithmetic_side_effects)] fn add(self, rhs: Self) -> Self::Output { let lhs_u64: u64 = self.into(); let rhs_u64: u64 = rhs.into(); (lhs_u64 + rhs_u64).into() } } impl Sub for $currency_type { type Output = Self; #[allow(clippy::arithmetic_side_effects)] fn sub(self, rhs: Self) -> Self::Output { let lhs_u64: u64 = self.into(); let rhs_u64: u64 = rhs.into(); (lhs_u64 - rhs_u64).into() } } impl Mul for $currency_type { type Output = Self; #[allow(clippy::arithmetic_side_effects)] fn mul(self, rhs: Self) -> Self::Output { let lhs_u64: u64 = self.into(); let rhs_u64: u64 = rhs.into(); (lhs_u64 * rhs_u64).into() } } impl Div for $currency_type { type Output = Self; #[allow(clippy::arithmetic_side_effects)] fn div(self, rhs: Self) -> Self::Output { let lhs_u64: u64 = self.into(); let rhs_u64: u64 = rhs.into(); (lhs_u64 / rhs_u64).into() } } impl Rem for $currency_type { type Output = Self; #[allow(clippy::arithmetic_side_effects)] fn rem(self, rhs: Self) -> Self::Output { let lhs_u64: u64 = self.into(); let rhs_u64: u64 = rhs.into(); (lhs_u64 % rhs_u64).into() } } impl AddAssign for $currency_type { #[allow(clippy::arithmetic_side_effects)] fn add_assign(&mut self, rhs: Self) { *self = *self + rhs; } } impl SubAssign for $currency_type { #[allow(clippy::arithmetic_side_effects)] fn sub_assign(&mut self, rhs: Self) { *self = *self - rhs; } } impl MulAssign for $currency_type { #[allow(clippy::arithmetic_side_effects)] fn mul_assign(&mut self, rhs: Self) { *self = *self * rhs; } } impl DivAssign for $currency_type { #[allow(clippy::arithmetic_side_effects)] fn div_assign(&mut self, rhs: Self) { *self = *self / rhs; } } }; } macro_rules! impl_approx { ($currency_type:ident) => { #[cfg(feature = "approx")] impl AbsDiffEq for $currency_type { type Epsilon = Self; fn default_epsilon() -> Self::Epsilon { u64::default_epsilon().into() } fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { u64::abs_diff_eq( &Into::::into(*self), &Into::::into(*other), epsilon.into(), ) } fn abs_diff_ne(&self, other: &Self, epsilon: Self::Epsilon) -> bool { u64::abs_diff_ne( &Into::::into(*self), &Into::::into(*other), epsilon.into(), ) } } }; } pub trait Token: ToFixed + Into + From + Clone + Copy + Eq + NumOps + Ord + PartialEq + PartialOrd + Display + Zero + One { const MAX: Self; const ZERO: Self; fn to_u64(&self) -> u64 { (*self).into() } fn saturating_add(&self, rhv: Self) -> Self { Into::::into(*self).saturating_add(rhv.into()).into() } #[allow(clippy::arithmetic_side_effects)] fn saturating_div(&self, rhv: Self) -> Self { Into::::into(*self).saturating_div(rhv.into()).into() } fn saturating_sub(&self, rhv: Self) -> Self { Into::::into(*self).saturating_sub(rhv.into()).into() } fn saturating_mul(&self, rhv: Self) -> Self { Into::::into(*self).saturating_mul(rhv.into()).into() } } impl_arithmetic_operators!(AlphaBalance); impl_approx!(AlphaBalance); impl_currency_reqs!(AlphaBalance); impl_arithmetic_operators!(TaoBalance); impl_approx!(TaoBalance); impl_currency_reqs!(TaoBalance); impl Token for AlphaBalance { const MAX: Self = Self(u64::MAX); const ZERO: Self = Self(0); } impl Token for TaoBalance { const MAX: Self = Self(u64::MAX); const ZERO: Self = Self(0); } // // Required explicitly by the bound // impl From for TaoBalance { // fn from(x: u32) -> Self { Self(x as u64) } // } impl Bounded for TaoBalance { fn min_value() -> Self { Self(u64::MIN) } fn max_value() -> Self { Self(u64::MAX) } } impl Saturating for TaoBalance { fn saturating_add(self, rhs: Self) -> Self { Self(self.0.saturating_add(rhs.0)) } fn saturating_sub(self, rhs: Self) -> Self { Self(self.0.saturating_sub(rhs.0)) } } ////////////////// impl CheckedNeg for TaoBalance { fn checked_neg(&self) -> Option { Some(*self) } } impl CheckedRem for TaoBalance { fn checked_rem(&self, rhs: &Self) -> Option { let lhs_u64: u64 = (*self).into(); let rhs_u64: u64 = (*rhs).into(); lhs_u64.checked_rem(rhs_u64).map(Into::into) } } impl Shl for TaoBalance { type Output = Self; #[allow(clippy::arithmetic_side_effects)] fn shl(self, rhs: u32) -> Self::Output { let lhs: u64 = self.into(); // Define semantics: saturate to 0 on oversized shift (instead of panic). // Alternatively, you could debug_assert! and return 0 in release. let shifted = lhs.checked_shl(rhs).unwrap_or(0); shifted.into() } } impl Shr for TaoBalance { type Output = Self; #[allow(clippy::arithmetic_side_effects)] fn shr(self, rhs: u32) -> Self::Output { let lhs: u64 = self.into(); let shifted = lhs.checked_shr(rhs).unwrap_or(0); shifted.into() } } impl Shl for TaoBalance { type Output = Self; #[allow(clippy::arithmetic_side_effects)] fn shl(self, rhs: usize) -> Self::Output { let lhs: u64 = self.into(); // Define semantics: saturate to 0 on oversized shift (instead of panic). // Alternatively, you could debug_assert! and return 0 in release. let shifted = lhs.checked_shl(rhs as u32).unwrap_or(0); shifted.into() } } impl Shr for TaoBalance { type Output = Self; #[allow(clippy::arithmetic_side_effects)] fn shr(self, rhs: usize) -> Self::Output { let lhs: u64 = self.into(); let shifted = lhs.checked_shr(rhs as u32).unwrap_or(0); shifted.into() } } impl Not for TaoBalance { type Output = Self; fn not(self) -> Self { Self(!self.0) } } impl BitAnd for TaoBalance { type Output = Self; fn bitand(self, rhs: Self) -> Self { Self(self.0 & rhs.0) } } impl BitOr for TaoBalance { type Output = Self; fn bitor(self, rhs: Self) -> Self { Self(self.0 | rhs.0) } } impl BitXor for TaoBalance { type Output = Self; fn bitxor(self, rhs: Self) -> Self { Self(self.0 ^ rhs.0) } } impl CheckedAdd for TaoBalance { fn checked_add(&self, rhs: &Self) -> Option { self.0.checked_add(rhs.0).map(Self) } } impl CheckedSub for TaoBalance { fn checked_sub(&self, rhs: &Self) -> Option { self.0.checked_sub(rhs.0).map(Self) } } impl CheckedMul for TaoBalance { fn checked_mul(&self, rhs: &Self) -> Option { self.0.checked_mul(rhs.0).map(Self) } } impl CheckedDiv for TaoBalance { fn checked_div(&self, rhs: &Self) -> Option { self.0.checked_div(rhs.0).map(Self) } } #[allow(clippy::arithmetic_side_effects)] impl CheckedShl for TaoBalance { fn checked_shl(&self, rhs: u32) -> Option { // Validate first (so we can return None), then use the operator as requested. let lhs: u64 = (*self).into(); lhs.checked_shl(rhs)?; Some((*self) << rhs) } } #[allow(clippy::arithmetic_side_effects)] impl CheckedShr for TaoBalance { fn checked_shr(&self, rhs: u32) -> Option { let lhs: u64 = (*self).into(); lhs.checked_shr(rhs)?; Some((*self) >> rhs) } } impl RemAssign for TaoBalance { #[allow(clippy::arithmetic_side_effects)] fn rem_assign(&mut self, rhs: Self) { *self = *self % rhs; } } impl PrimInt for TaoBalance { fn count_ones(self) -> u32 { self.0.count_ones() } fn count_zeros(self) -> u32 { self.0.count_zeros() } fn leading_zeros(self) -> u32 { self.0.leading_zeros() } fn trailing_zeros(self) -> u32 { self.0.trailing_zeros() } fn rotate_left(self, n: u32) -> Self { Self(self.0.rotate_left(n)) } fn rotate_right(self, n: u32) -> Self { Self(self.0.rotate_right(n)) } fn signed_shl(self, n: u32) -> Self { // For unsigned integers, num_traits defines signed_shl/shr as normal shifts. Self(self.0.wrapping_shl(n)) } fn signed_shr(self, n: u32) -> Self { Self(self.0.wrapping_shr(n)) } fn unsigned_shl(self, n: u32) -> Self { Self(self.0.wrapping_shl(n)) } fn unsigned_shr(self, n: u32) -> Self { Self(self.0.wrapping_shr(n)) } fn swap_bytes(self) -> Self { Self(self.0.swap_bytes()) } fn from_be(x: Self) -> Self { Self(u64::from_be(x.0)) } fn from_le(x: Self) -> Self { Self(u64::from_le(x.0)) } fn to_be(self) -> Self { Self(self.0.to_be()) } fn to_le(self) -> Self { Self(self.0.to_le()) } fn pow(self, exp: u32) -> Self { Self(self.0.pow(exp)) } } impl Unsigned for TaoBalance {} impl Num for TaoBalance { type FromStrRadixErr = ::FromStrRadixErr; fn from_str_radix(s: &str, radix: u32) -> Result { u64::from_str_radix(s, radix).map(Self) } } impl NumCast for TaoBalance { fn from(n: T) -> Option { n.to_u64().map(Self) } } impl ToPrimitive for TaoBalance { fn to_i64(&self) -> Option { self.0.to_i64() } fn to_u64(&self) -> Option { Some(self.0) } fn to_u128(&self) -> Option { Some(self.0 as u128) } fn to_usize(&self) -> Option { self.0.to_usize() } } impl FromPrimitive for TaoBalance { fn from_u64(n: u64) -> Option { Some(Self(n)) } fn from_u128(n: u128) -> Option { if n <= u64::MAX as u128 { Some(Self(n as u64)) } else { None } } fn from_usize(n: usize) -> Option { Some(Self(n as u64)) } fn from_i64(n: i64) -> Option { if n >= 0 { Some(Self(n as u64)) } else { None } } } impl MultiplyRational for TaoBalance { fn multiply_rational(self, n: Self, d: Self, r: Rounding) -> Option { let a: u64 = self.into(); let n: u64 = n.into(); let d: u64 = d.into(); a.multiply_rational(n, d, r).map(Into::into) } } impl From for TaoBalance { fn from(x: u16) -> Self { TaoBalance(x as u64) } } impl From for TaoBalance { fn from(n: u128) -> Self { if n <= u64::MAX as u128 { Self(n as u64) } else { Self(u64::MAX) } } } impl From for TaoBalance { fn from(n: usize) -> Self { Self(n as u64) } } impl From for TaoBalance { fn from(n: sp_core::U256) -> Self { if let Ok(n_u64) = n.try_into() { Self(n_u64) } else { Self(u64::MAX) } } } #[allow(clippy::from_over_into)] impl Into for TaoBalance { fn into(self) -> usize { self.0 as usize } } #[allow(clippy::from_over_into)] impl Into for TaoBalance { fn into(self) -> u128 { self.0 as u128 } } #[allow(clippy::from_over_into)] impl Into for TaoBalance { fn into(self) -> u32 { self.0 as u32 } } #[allow(clippy::from_over_into)] impl Into for TaoBalance { fn into(self) -> u16 { self.0 as u16 } } #[allow(clippy::from_over_into)] impl Into for TaoBalance { fn into(self) -> u8 { self.0 as u8 } } #[allow(clippy::from_over_into)] impl Into for TaoBalance { fn into(self) -> sp_core::U256 { sp_core::U256::from(self.0) } } #[allow(clippy::from_over_into)] #[cfg(feature = "std")] impl Into for TaoBalance { fn into(self) -> NumberOrHex { NumberOrHex::Number(self.0) } } pub struct ConstTao; impl Get for ConstTao { fn get() -> TaoBalance { TaoBalance::new(N) } }