diff --git a/gradually-update/src/tests.rs b/gradually-update/src/tests.rs
index 9d8b0e1267ee49d3e41107b34d579f0ac75ff837..635c5f809428b51997b560197803521fb52b6a1f 100644
--- a/gradually-update/src/tests.rs
+++ b/gradually-update/src/tests.rs
@@ -5,7 +5,7 @@
 use super::*;
 use frame_support::{assert_noop, assert_ok, traits::OnFinalize};
 use mock::{ExtBuilder, GraduallyUpdateModule, Origin, Runtime, System, TestEvent};
-use orml_utilities::FixedU128;
+use orml_utilities::{FixedU128, FixedUnsignedNumber};
 use sp_runtime::Permill;
 
 fn storage_set(key: &Vec<u8>, value: &Vec<u8>) {
@@ -303,8 +303,8 @@ fn fixedu128_should_work() {
 	ExtBuilder::default().build().execute_with(|| {
 		let update = GraduallyUpdate {
 			key: vec![1],
-			target_value: FixedU128::from_rational(30, 1).encode(),
-			per_block: FixedU128::from_rational(1, 1).encode(),
+			target_value: FixedU128::saturating_from_rational(30, 1).encode(),
+			per_block: FixedU128::saturating_from_rational(1, 1).encode(),
 		};
 		assert_ok!(GraduallyUpdateModule::gradually_update(Origin::ROOT, update.clone()));
 		assert_eq!(storage_get(&update.key), vec![]);
diff --git a/prices/src/lib.rs b/prices/src/lib.rs
index 4b07248fd61f5d21d8d4a148b9a32f081c018483..8944e79074b1fcfd29cf879389754e3052a33f10 100644
--- a/prices/src/lib.rs
+++ b/prices/src/lib.rs
@@ -3,7 +3,7 @@
 use frame_support::Parameter;
 use orml_traits::{DataProvider, PriceProvider};
 use orml_utilities::FixedU128;
-use sp_runtime::traits::{MaybeSerializeDeserialize, Member};
+use sp_runtime::traits::{CheckedDiv, MaybeSerializeDeserialize, Member};
 use sp_std::marker::PhantomData;
 
 pub type Price = FixedU128;
diff --git a/prices/src/tests.rs b/prices/src/tests.rs
index 231f5d922e971804a17a88ba6d98fce6ea709094..997d2cd53478b7326f31f6aa36b5b93915ff5fe6 100644
--- a/prices/src/tests.rs
+++ b/prices/src/tests.rs
@@ -3,14 +3,15 @@
 #![cfg(test)]
 
 use super::*;
+use orml_utilities::FixedUnsignedNumber;
 
 pub struct MockDataProvider;
 impl DataProvider<u32, Price> for MockDataProvider {
 	fn get(currency: &u32) -> Option<Price> {
 		match currency {
-			0 => Some(Price::from_parts(0)),
-			1 => Some(Price::from_parts(1)),
-			2 => Some(Price::from_parts(2)),
+			0 => Some(Price::from_inner(0)),
+			1 => Some(Price::from_inner(1)),
+			2 => Some(Price::from_inner(2)),
 			_ => None,
 		}
 	}
@@ -20,8 +21,14 @@ type TestPriceProvider = DefaultPriceProvider<u32, MockDataProvider>;
 
 #[test]
 fn get_price_should_work() {
-	assert_eq!(TestPriceProvider::get_price(1, 2), Some(Price::from_rational(1, 2)));
-	assert_eq!(TestPriceProvider::get_price(2, 1), Some(Price::from_rational(2, 1)));
+	assert_eq!(
+		TestPriceProvider::get_price(1, 2),
+		Some(Price::saturating_from_rational(1, 2))
+	);
+	assert_eq!(
+		TestPriceProvider::get_price(2, 1),
+		Some(Price::saturating_from_rational(2, 1))
+	);
 }
 
 #[test]
@@ -35,5 +42,5 @@ fn price_is_none_should_not_panic() {
 fn price_is_zero_should_not_panic() {
 	assert_eq!(TestPriceProvider::get_price(0, 0), None);
 	assert_eq!(TestPriceProvider::get_price(1, 0), None);
-	assert_eq!(TestPriceProvider::get_price(0, 1), Some(Price::from_parts(0)));
+	assert_eq!(TestPriceProvider::get_price(0, 1), Some(Price::from_inner(0)));
 }
diff --git a/utilities/Cargo.toml b/utilities/Cargo.toml
index a2642b900ca98b9a8c8716b366413e6f3f406c3c..19b6e63f101103533a62423864474cf65bb2488a 100644
--- a/utilities/Cargo.toml
+++ b/utilities/Cargo.toml
@@ -14,6 +14,7 @@ sp-core = { version = "2.0.0-rc1", default-features = false }
 sp-runtime = { version = "2.0.0-rc1", default-features = false }
 sp-io = { version = "2.0.0-rc1", default-features = false }
 sp-std = { version = "2.0.0-rc1", default-features = false }
+sp-arithmetic= { version = "2.0.0-rc1", default-features = false }
 
 frame-system = { version = "2.0.0-rc1", default-features = false }
 frame-support = { version = "2.0.0-rc1", default-features = false }
diff --git a/utilities/src/fixed_u128.rs b/utilities/src/fixed_u128.rs
index 5146ed05f6e4134efdb200372e4f0a4279b67d3b..2b3adf0093290759dfb0316eec0a7d0c4ea105b8 100644
--- a/utilities/src/fixed_u128.rs
+++ b/utilities/src/fixed_u128.rs
@@ -1,4 +1,5 @@
 use codec::{CompactAs, Decode, Encode};
+use sp_arithmetic::traits::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, Zero};
 use sp_core::U256;
 use sp_runtime::{
 	traits::{Bounded, Saturating, UniqueSaturatedInto},
@@ -6,7 +7,8 @@ use sp_runtime::{
 };
 use sp_std::{
 	convert::{Into, TryFrom, TryInto},
-	fmt,
+	fmt::{self, Debug},
+	ops::{self, Add, Div, Mul, Sub},
 };
 
 #[cfg(feature = "std")]
@@ -19,145 +21,293 @@ pub struct FixedU128(u128);
 
 const DIV: u128 = 1_000_000_000_000_000_000;
 
-impl FixedU128 {
-	/// Create self from a natural number.
+/// Integer types that can be used to interact with `FixedPointNumber` implementations.
+pub trait FixedPointOperand:
+	Copy
+	+ Clone
+	+ Bounded
+	+ Zero
+	+ Saturating
+	+ PartialOrd
+	+ UniqueSaturatedInto<u128>
+	+ TryFrom<u128>
+	+ TryInto<u128>
+	+ TryFrom<U256>
+{
+}
+
+impl FixedPointOperand for i128 {}
+impl FixedPointOperand for u128 {}
+impl FixedPointOperand for i64 {}
+impl FixedPointOperand for u64 {}
+impl FixedPointOperand for i32 {}
+impl FixedPointOperand for u32 {}
+impl FixedPointOperand for i16 {}
+impl FixedPointOperand for u16 {}
+impl FixedPointOperand for i8 {}
+impl FixedPointOperand for u8 {}
+
+pub trait FixedUnsignedNumber:
+	Sized
+	+ Copy
+	+ Default
+	+ fmt::Debug
+	+ Saturating
+	+ Bounded
+	+ Eq
+	+ PartialEq
+	+ Ord
+	+ PartialOrd
+	+ CheckedSub
+	+ CheckedAdd
+	+ CheckedMul
+	+ CheckedDiv
+	+ Add
+	+ Sub
+	+ Div
+	+ Mul
+	+ Zero
+	+ One
+{
+	type Inner: Debug + One + CheckedMul + CheckedDiv + FixedPointOperand + Into<U256> + Into<u128>;
+
+	/// Precision of this fixed point implementation. It should be a power of `10`.
+	const DIV: Self::Inner;
+
+	/// Precision of this fixed point implementation.
+	fn accuracy() -> Self::Inner {
+		Self::DIV
+	}
+
+	/// Create `self` from a natural number.
 	///
 	/// Note that this might be lossy.
-	pub fn from_natural(int: u128) -> Self {
-		Self(int.saturating_mul(DIV))
+	fn from_natural(int: Self::Inner) -> Self;
+
+	/// Builds this type from an integer number.
+	fn from_inner(int: Self::Inner) -> Self;
+
+	/// Consumes `self` and returns the inner raw value.
+	fn into_inner(self) -> Self::Inner;
+
+	/// Creates self from an integer number `int`.
+	///
+	/// Returns `Self::max` or `Self::min` if `int` exceeds accuracy.
+	fn saturating_from_integer<N: UniqueSaturatedInto<Self::Inner> + PartialOrd + Zero>(int: N) -> Self {
+		if int < N::zero() {
+			return Self::min_value();
+		}
+
+		Self::from_inner(int.unique_saturated_into().saturating_mul(Self::DIV))
 	}
 
-	/// Accuracy of `FixedU128`.
-	pub const fn accuracy() -> u128 {
-		DIV
+	/// Creates `self` from an integer number `int`.
+	///
+	/// Returns `None` if `int` exceeds accuracy.
+	fn checked_from_integer(int: Self::Inner) -> Option<Self> {
+		int.checked_mul(&Self::DIV).map(Self::from_inner)
 	}
 
-	/// Raw constructor. Equal to `parts / DIV`.
-	pub fn from_parts(parts: u128) -> Self {
-		Self(parts)
+	/// Creates `self` from a rational number. Equal to `n / d`.
+	///
+	/// Panics if `d = 0`. Returns `Self::max` or `Self::min` if `n / d` exceeds accuracy.
+	fn saturating_from_rational<N: FixedPointOperand, D: FixedPointOperand>(n: N, d: D) -> Self {
+		if d == D::zero() {
+			panic!("attempt to divide by zero")
+		}
+		Self::checked_from_rational(n, d).unwrap_or_else(|| to_bound(n, d))
 	}
 
-	/// Creates self from a rational number. Equal to `n/d`.
+	/// Creates `self` from a rational number. Equal to `n / d`.
 	///
-	/// Note that this might be lossy.
-	pub fn from_rational<N: UniqueSaturatedInto<u128>>(n: N, d: N) -> Self {
+	/// Returns `None` if `d == 0` or `n / d` exceeds accuracy.
+	fn checked_from_rational<N: FixedPointOperand, D: FixedPointOperand>(n: N, d: D) -> Option<Self> {
+		if d == D::zero() {
+			return None;
+		}
+
 		// this should really be `N: Into<U256>` or else might give wrong result
 		// TODO: Should have a better way to enforce this requirement
-		let n = n.unique_saturated_into();
+		// let n = n.unique_saturated_into();
+		// let d = d.unique_saturated_into();
+		// let d = U256::from(d);
+
+		let n: u128 = (n).try_into().ok()?;
 		let n = U256::from(n);
-		let d = d.unique_saturated_into();
+		let d: u128 = (d).try_into().ok()?;
 		let d = U256::from(d);
-		Self(
-			(n.saturating_mul(DIV.into()) / d.max(U256::one()))
-				.try_into()
-				.unwrap_or_else(|_| Bounded::max_value()),
-		)
+
+		n.checked_mul(U256::from(Self::DIV.unique_saturated_into()))
+			.and_then(|n| n.checked_div(d))
+			.and_then(|n| n.try_into().ok())
+			.map(Self::from_inner)
 	}
 
-	/// Consume self and return the inner raw `u128` value.
+	/// Checked mul for int type `N`. Equal to `self *  n`.
 	///
-	/// Note this is a low level function, as the returned value is represented with accuracy.
-	pub fn deconstruct(self) -> u128 {
-		self.0
+	/// Returns `None` if the result does not fit in `N`.
+	fn checked_mul_int<N: FixedPointOperand>(&self, other: N) -> Option<N> {
+		let lhs: U256 = self.into_inner().into();
+		let rhs: u128 = other.try_into().ok()?;
+		let rhs: U256 = U256::from(rhs);
+
+		lhs.checked_mul(rhs)
+			.and_then(|n| n.checked_div(U256::from(Self::DIV.unique_saturated_into())))
+			.and_then(|n| n.try_into().ok())
+			.and_then(from_u128)
 	}
 
-	/// Takes the reciprocal(inverse) of FixedU128, 1/x
-	pub fn recip(&self) -> Option<Self> {
-		Self::from_natural(1u128).checked_div(self)
+	/// Saturating multiplication for integer type `N`. Equal to `self * n`.
+	///
+	/// Returns `N::min` or `N::max` if the result does not fit in `N`.
+	fn saturating_mul_int<N: FixedPointOperand>(self, n: N) -> N {
+		self.checked_mul_int(n)
+			.unwrap_or_else(|| to_bound(self.into_inner(), n))
 	}
 
-	/// Checked add. Same semantic to `num_traits::CheckedAdd`.
-	pub fn checked_add(&self, rhs: &Self) -> Option<Self> {
-		self.0.checked_add(rhs.0).map(Self)
+	/// Checked division for integer type `N`. Equal to `self / d`.
+	///
+	/// Returns `None` if the result does not fit in `N` or `d == 0`.
+	fn checked_div_int<N: FixedPointOperand>(&self, other: N) -> Option<N> {
+		let lhs: u128 = self.into_inner().into();
+		let rhs: u128 = other.try_into().ok()?;
+
+		lhs.checked_div(rhs)
+			.and_then(|n| n.checked_div(Self::DIV.unique_saturated_into()))
+			.and_then(from_u128)
 	}
 
-	/// Checked sub. Same semantic to `num_traits::CheckedSub`.
-	pub fn checked_sub(&self, rhs: &Self) -> Option<Self> {
-		self.0.checked_sub(rhs.0).map(Self)
+	/// Saturating division for integer type `N`. Equal to `self / d`.
+	///
+	/// Panics if `d == 0`. Returns `N::min` or `N::max` if the result does not fit in `N`.
+	fn saturating_div_int<N: FixedPointOperand>(self, d: N) -> N {
+		if d == N::zero() {
+			panic!("attempt to divide by zero")
+		}
+		self.checked_div_int(d)
+			.unwrap_or_else(|| to_bound(self.into_inner(), d))
 	}
 
-	/// Checked mul. Same semantic to `num_traits::CheckedMul`.
-	pub fn checked_mul(&self, rhs: &Self) -> Option<Self> {
-		if let Some(r) = U256::from(self.0)
-			.checked_mul(U256::from(rhs.0))
-			.and_then(|n| n.checked_div(U256::from(DIV)))
-		{
-			if let Ok(r) = TryInto::<u128>::try_into(r) {
-				return Some(Self(r));
-			}
-		}
+	/// Saturating multiplication for integer type `N`, adding the result back.
+	/// Equal to `self * n + n`.
+	///
+	/// Returns `N::min` or `N::max` if the multiplication or final result does not fit in `N`.
+	fn saturating_mul_acc_int<N: FixedPointOperand>(self, n: N) -> N {
+		self.saturating_mul_int(n).saturating_add(n)
+	}
 
-		None
+	/// Takes the reciprocal (inverse). Equal to `1 / self`.
+	///
+	/// Returns `None` if `self = 0`.
+	fn reciprocal(self) -> Option<Self> {
+		Self::one().checked_div(&self)
 	}
 
-	/// Checked div. Same semantic to `num_traits::CheckedDiv`.
-	pub fn checked_div(&self, rhs: &Self) -> Option<Self> {
-		if let Some(r) = U256::from(self.0)
-			.checked_mul(U256::from(DIV))
-			.and_then(|n| n.checked_div(U256::from(rhs.0)))
-		{
-			if let Ok(r) = TryInto::<u128>::try_into(r) {
-				return Some(Self(r));
-			}
+	/// Returns the integer part.
+	fn trunc(self) -> Self {
+		self.into_inner()
+			.checked_div(&Self::DIV)
+			.expect("panics only if DIV is zero, DIV is not zero; qed")
+			.checked_mul(&Self::DIV)
+			.map(Self::from_inner)
+			.expect("can not overflow since fixed number is >= integer part")
+	}
+
+	/// Returns the fractional part.
+	///
+	/// Note: the returned fraction will be non-negative for negative numbers,
+	/// except in the case where the integer part is zero.
+	fn frac(self) -> Self {
+		let integer = self.trunc();
+
+		self.saturating_sub(integer)
+	}
+
+	/// Returns the smallest integer greater than or equal to a number.
+	///
+	/// Saturates to `Self::max` (truncated) if the result does not fit.
+	fn ceil(self) -> Self {
+		if self.is_zero() {
+			return self.trunc();
 		}
+		self.saturating_add(Self::one()).trunc()
+	}
 
-		None
+	/// Returns the largest integer less than or equal to a number.
+	///
+	/// Saturates to `Self::min` (truncated) if the result does not fit.
+	fn floor(self) -> Self {
+		self.trunc()
 	}
 
-	/// Checked mul for int type `N`.
-	pub fn checked_mul_int<N>(&self, other: &N) -> Option<N>
-	where
-		N: Copy + TryFrom<u128> + TryInto<u128>,
-	{
-		if let Ok(n) = N::try_into(*other) {
-			if let Some(n) = U256::from(self.0)
-				.checked_mul(U256::from(n))
-				.and_then(|n| n.checked_div(U256::from(DIV)))
-			{
-				if let Ok(r) = TryInto::<u128>::try_into(n) {
-					if let Ok(r) = TryInto::<N>::try_into(r) {
-						return Some(r);
-					}
-				}
-			}
+	/// Returns the number rounded to the nearest integer. Rounds half-way cases away from 0.0.
+	///
+	/// Saturates to `Self::min` or `Self::max` (truncated) if the result does not fit.
+	fn round(self) -> Self {
+		let n = self.frac().saturating_mul(Self::saturating_from_integer(10));
+		if n < Self::saturating_from_integer(5) {
+			self.floor()
+		} else {
+			self.ceil()
 		}
+	}
+}
+
+impl FixedUnsignedNumber for FixedU128 {
+	type Inner = u128;
 
-		None
+	const DIV: Self::Inner = DIV;
+
+	fn from_natural(n: Self::Inner) -> Self {
+		Self::from_inner(n.saturating_mul(Self::DIV))
 	}
 
-	/// Checked mul for int type `N`.
-	pub fn saturating_mul_int<N>(&self, other: &N) -> N
-	where
-		N: Copy + TryFrom<u128> + TryInto<u128> + Bounded,
-	{
-		self.checked_mul_int(other).unwrap_or_else(Bounded::max_value)
+	fn from_inner(n: Self::Inner) -> Self {
+		Self(n)
 	}
 
-	/// Checked div for int type `N`.
-	pub fn checked_div_int<N>(&self, other: &N) -> Option<N>
-	where
-		N: Copy + TryFrom<u128> + TryInto<u128>,
-	{
-		if let Ok(n) = N::try_into(*other) {
-			if let Some(n) = self.0.checked_div(n).and_then(|n| n.checked_div(DIV)) {
-				if let Ok(r) = TryInto::<N>::try_into(n) {
-					return Some(r);
-				}
-			}
-		}
+	fn into_inner(self) -> Self::Inner {
+		self.0
+	}
+}
 
-		None
+/// Returns `R::max` if the sign of `n * m` is positive, `R::min` otherwise.
+fn to_bound<N: FixedPointOperand, D: FixedPointOperand, R: Bounded + Zero>(n: N, m: D) -> R {
+	if n < N::zero() {
+		return R::zero();
 	}
+	if m < D::zero() {
+		return R::zero();
+	}
+
+	R::max_value()
+}
+
+fn from_u128<N: FixedPointOperand>(n: u128) -> Option<N> {
+	let r: N = n.try_into().ok()?;
+	Some(r)
+}
 
-	pub fn zero() -> Self {
+impl Zero for FixedU128 {
+	fn zero() -> Self {
 		Self(0)
 	}
 
-	pub fn is_zero(&self) -> bool {
+	fn is_zero(&self) -> bool {
 		self.0 == 0
 	}
 }
 
+impl One for FixedU128 {
+	fn one() -> Self {
+		Self(DIV)
+	}
+
+	fn is_one(&self) -> bool {
+		self.0 == DIV
+	}
+}
+
 impl Saturating for FixedU128 {
 	fn saturating_add(self, rhs: Self) -> Self {
 		Self(self.0.saturating_add(rhs.0))
@@ -177,13 +327,13 @@ impl Saturating for FixedU128 {
 
 	fn saturating_pow(self, exp: usize) -> Self {
 		if exp == 0 {
-			return Self::from_natural(1);
+			return Self::saturating_from_integer(1);
 		}
 
 		let exp = exp as u64;
 		let msb_pos = 64 - exp.leading_zeros();
 
-		let mut result = Self::from_natural(1);
+		let mut result = Self::saturating_from_integer(1);
 		let mut pow_val = self;
 		for i in 0..msb_pos {
 			if ((1 << i) & exp) > 0 {
@@ -195,6 +345,76 @@ impl Saturating for FixedU128 {
 	}
 }
 
+impl ops::Add for FixedU128 {
+	type Output = Self;
+
+	fn add(self, rhs: Self) -> Self::Output {
+		Self(self.0 + rhs.0)
+	}
+}
+
+impl ops::Sub for FixedU128 {
+	type Output = Self;
+
+	fn sub(self, rhs: Self) -> Self::Output {
+		Self(self.0 - rhs.0)
+	}
+}
+
+impl ops::Mul for FixedU128 {
+	type Output = Self;
+
+	fn mul(self, rhs: Self) -> Self::Output {
+		self.checked_mul(&rhs)
+			.unwrap_or_else(|| panic!("attempt to multiply with overflow"))
+	}
+}
+
+impl ops::Div for FixedU128 {
+	type Output = Self;
+
+	fn div(self, rhs: Self) -> Self::Output {
+		if rhs.0 == 0 {
+			panic!("attempt to divide by zero")
+		}
+
+		self.checked_div(&rhs)
+			.unwrap_or_else(|| panic!("attempt to divide with overflow"))
+	}
+}
+
+impl CheckedAdd for FixedU128 {
+	fn checked_add(&self, rhs: &Self) -> Option<Self> {
+		self.0.checked_add(rhs.0).map(Self)
+	}
+}
+
+impl CheckedSub for FixedU128 {
+	fn checked_sub(&self, rhs: &Self) -> Option<Self> {
+		self.0.checked_sub(rhs.0).map(Self)
+	}
+}
+
+impl CheckedMul for FixedU128 {
+	fn checked_mul(&self, rhs: &Self) -> Option<Self> {
+		U256::from(self.0)
+			.checked_mul(U256::from(rhs.0))
+			.and_then(|n| n.checked_div(U256::from(DIV)))
+			.and_then(|n| TryInto::<u128>::try_into(n).ok())
+			.map(Self)
+	}
+}
+
+impl CheckedDiv for FixedU128 {
+	fn checked_div(&self, rhs: &Self) -> Option<Self> {
+		U256::from(self.0)
+			.checked_mul(U256::from(DIV))
+			.and_then(|n| n.checked_div(U256::from(rhs.0)))
+			.and_then(|n| TryInto::<u128>::try_into(n).ok())
+			.map(Self)
+	}
+}
+
 impl Bounded for FixedU128 {
 	fn max_value() -> Self {
 		Self(u128::max_value())
@@ -218,27 +438,50 @@ impl fmt::Debug for FixedU128 {
 	}
 }
 
+#[cfg(feature = "std")]
+impl sp_std::fmt::Display for FixedU128 {
+	fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
+		write!(f, "{}", self.0)
+	}
+}
+
+#[cfg(feature = "std")]
+impl sp_std::str::FromStr for FixedU128 {
+	type Err = &'static str;
+
+	fn from_str(s: &str) -> Result<Self, Self::Err> {
+		let inner: u128 = s.parse().map_err(|_| "invalid string input for fixed u128")?;
+		Ok(Self::from_inner(inner))
+	}
+}
+
+impl From<u128> for FixedU128 {
+	fn from(n: u128) -> Self {
+		Self::saturating_from_integer(n)
+	}
+}
+
 impl From<Permill> for FixedU128 {
 	fn from(val: Permill) -> Self {
-		FixedU128::from_rational(val.deconstruct(), Permill::ACCURACY)
+		FixedU128::saturating_from_rational(val.deconstruct(), Permill::ACCURACY)
 	}
 }
 
 impl From<Percent> for FixedU128 {
 	fn from(val: Percent) -> Self {
-		FixedU128::from_rational(val.deconstruct(), Percent::ACCURACY)
+		FixedU128::saturating_from_rational(val.deconstruct(), Percent::ACCURACY)
 	}
 }
 
 impl From<Perbill> for FixedU128 {
 	fn from(val: Perbill) -> Self {
-		FixedU128::from_rational(val.deconstruct(), Perbill::ACCURACY)
+		FixedU128::saturating_from_rational(val.deconstruct(), Perbill::ACCURACY)
 	}
 }
 
 impl From<Perquintill> for FixedU128 {
 	fn from(val: Perquintill) -> Self {
-		FixedU128::from_rational(val.deconstruct(), Perquintill::ACCURACY)
+		FixedU128::saturating_from_rational(val.deconstruct(), Perquintill::ACCURACY)
 	}
 }
 
@@ -250,7 +493,7 @@ impl FixedU128 {
 
 	fn try_from_u128_str(s: &str) -> Result<Self, &'static str> {
 		let parts: u128 = s.parse().map_err(|_| "invalid string input")?;
-		Ok(Self::from_parts(parts))
+		Ok(Self::from_inner(parts))
 	}
 }
 
@@ -285,14 +528,51 @@ mod tests {
 	use sp_runtime::{Perbill, Percent, Permill, Perquintill};
 
 	fn max() -> FixedU128 {
-		FixedU128::from_parts(u128::max_value())
+		FixedU128::from_inner(u128::max_value())
+	}
+	#[test]
+	fn to_bound_works() {
+		let a = 1i32;
+		let b = 1i32;
+
+		// Pos + Pos => Max.
+		assert_eq!(to_bound::<_, _, i32>(a, b), i32::max_value());
+
+		let a = -1i32;
+		let b = -1i32;
+
+		// Neg + Neg => 0.
+		assert_eq!(to_bound::<_, _, i32>(a, b), 0);
+
+		let a = 1i32;
+		let b = -1i32;
+
+		// Pos + Neg => 0.
+		assert_eq!(to_bound::<_, _, i32>(a, b), 0);
+
+		let a = -1i32;
+		let b = 1i32;
+
+		// Neg + Pos => 0.
+		assert_eq!(to_bound::<_, _, i32>(a, b), 0);
+
+		let a = 1i32;
+		let b = -1i32;
+
+		// Pos + Neg => Min (unsigned).
+		assert_eq!(to_bound::<_, _, u32>(a, b), 0);
 	}
 
 	#[test]
 	fn fixed128_semantics() {
-		assert_eq!(FixedU128::from_rational(5, 2).0, 5 * 1_000_000_000_000_000_000 / 2);
-		assert_eq!(FixedU128::from_rational(5, 2), FixedU128::from_rational(10, 4));
-		assert_eq!(FixedU128::from_rational(5, 0), FixedU128::from_rational(5, 1));
+		assert_eq!(
+			FixedU128::saturating_from_rational(5, 2).into_inner(),
+			5 * 1_000_000_000_000_000_000 / 2
+		);
+		assert_eq!(
+			FixedU128::saturating_from_rational(5, 2),
+			FixedU128::saturating_from_rational(10, 4)
+		);
 
 		// biggest value that can be created.
 		assert_ne!(max(), FixedU128::from_natural(340_282_366_920_938_463_463));
@@ -306,45 +586,30 @@ mod tests {
 		assert_eq!(a.checked_add(&b), Some(FixedU128::from_natural(1 + 2)));
 		assert_eq!(a.checked_sub(&b), Some(FixedU128::from_natural(2 - 1)));
 		assert_eq!(a.checked_mul(&b), Some(FixedU128::from_natural(1 * 2)));
-		assert_eq!(a.checked_div(&b), Some(FixedU128::from_rational(2, 1)));
+		assert_eq!(a.checked_div(&b), Some(FixedU128::saturating_from_rational(2, 1)));
 
-		let a = FixedU128::from_rational(5, 2);
-		let b = FixedU128::from_rational(3, 2);
-		assert_eq!(a.checked_add(&b), Some(FixedU128::from_rational(8, 2)));
-		assert_eq!(a.checked_sub(&b), Some(FixedU128::from_rational(2, 2)));
-		assert_eq!(a.checked_mul(&b), Some(FixedU128::from_rational(15, 4)));
-		assert_eq!(a.checked_div(&b), Some(FixedU128::from_rational(10, 6)));
+		let a = FixedU128::saturating_from_rational(5, 2);
+		let b = FixedU128::saturating_from_rational(3, 2);
+		assert_eq!(a.checked_add(&b), Some(FixedU128::saturating_from_rational(8, 2)));
+		assert_eq!(a.checked_sub(&b), Some(FixedU128::saturating_from_rational(2, 2)));
+		assert_eq!(a.checked_mul(&b), Some(FixedU128::saturating_from_rational(15, 4)));
+		assert_eq!(a.checked_div(&b), Some(FixedU128::saturating_from_rational(10, 6)));
 
 		let a = FixedU128::from_natural(120);
 		let b = 2i32;
-		assert_eq!(a.checked_div_int::<i32>(&b), Some(60));
+		assert_eq!(a.checked_div_int::<i32>(b), Some(60));
 
-		let a = FixedU128::from_rational(20, 1);
+		let a = FixedU128::saturating_from_rational(20, 1);
 		let b = 2i32;
-		assert_eq!(a.checked_div_int::<i32>(&b), Some(10));
+		assert_eq!(a.checked_div_int::<i32>(b), Some(10));
 
 		let a = FixedU128::from_natural(120);
 		let b = 2i32;
-		assert_eq!(a.checked_mul_int::<i32>(&b), Some(240));
+		assert_eq!(a.checked_mul_int::<i32>(b), Some(240));
 
-		let a = FixedU128::from_rational(1, 2);
+		let a = FixedU128::saturating_from_rational(1, 2);
 		let b = 20i32;
-		assert_eq!(a.checked_mul_int::<i32>(&b), Some(10));
-	}
-
-	#[test]
-	fn saturating_mul_int_works() {
-		let a = FixedU128::from_rational(10, 1);
-		let b = u32::max_value() / 5;
-		assert_eq!(a.saturating_mul_int(&b), u32::max_value());
-
-		let a = FixedU128::from_rational(3, 1);
-		let b = 100u8;
-		assert_eq!(a.saturating_mul_int(&b), 255u8);
-
-		let a = FixedU128::from_rational(10, 1);
-		let b = 123;
-		assert_eq!(a.saturating_mul_int(&b), 1230);
+		assert_eq!(a.checked_mul_int::<i32>(b), Some(10));
 	}
 
 	#[test]
@@ -359,81 +624,531 @@ mod tests {
 	}
 
 	#[test]
-	fn checked_div_with_zero_should_be_none() {
-		let a = FixedU128::from_natural(1);
-		let b = FixedU128::from_natural(0);
-		assert_eq!(a.checked_div(&b), None);
+	fn op_checked_add_overflow_should_be_none() {
+		let a = FixedU128::max_value();
+		let b = 1.into();
+		assert!(a.checked_add(&b).is_none());
 	}
 
 	#[test]
-	fn checked_div_int_with_zero_should_be_none() {
-		let a = FixedU128::from_natural(1);
-		let b = 0i32;
-		assert_eq!(a.checked_div_int(&b), None);
+	#[should_panic(expected = "attempt to add with overflow")]
+	fn op_add_overflow_should_panic() {
+		let a = FixedU128::max_value();
+		let b = 1.into();
+		let _c = a + b;
 	}
 
 	#[test]
-	fn under_flow_should_be_none() {
-		let a = FixedU128::from_natural(2);
-		let b = FixedU128::from_natural(3);
-		assert_eq!(a.checked_sub(&b), None);
+	fn op_add_works() {
+		let a = FixedU128::saturating_from_rational(1, 2);
+		let b = FixedU128::saturating_from_rational(5, 3);
+		assert_eq!(FixedU128::saturating_from_rational(13, 6), a + b);
+	}
+
+	#[test]
+	fn op_checked_sub_underflow_should_be_none() {
+		let a = FixedU128::min_value();
+		let b = 1.into();
+		assert!(a.checked_sub(&b).is_none());
+	}
+
+	#[test]
+	#[should_panic(expected = "attempt to subtract with overflow")]
+	fn op_sub_underflow_should_panic() {
+		let a = FixedU128::min_value();
+		let b = 1.into();
+		let _c = a - b;
+	}
+
+	#[test]
+	fn op_sub_works() {
+		let a = FixedU128::saturating_from_rational(1, 2);
+		let b = FixedU128::saturating_from_rational(5, 3);
+		assert_eq!(FixedU128::saturating_from_rational(7, 6), b - a);
+	}
+
+	#[test]
+	fn op_checked_mul_overflow_should_be_none() {
+		let a = FixedU128::max_value();
+		let b = 2.into();
+		assert!(a.checked_mul(&b).is_none());
+	}
+
+	#[test]
+	#[should_panic(expected = "attempt to multiply with overflow")]
+	fn op_mul_overflow_should_panic() {
+		let a = FixedU128::max_value();
+		let b = 2.into();
+		let _c = a * b;
+	}
+
+	#[test]
+	fn op_mul_works() {
+		let a = FixedU128::saturating_from_rational(1, 2);
+		let b = FixedU128::saturating_from_rational(5, 3);
+		assert_eq!(FixedU128::saturating_from_rational(5, 6), a * b);
+	}
+
+	#[test]
+	fn op_checked_div_with_zero_should_be_none() {
+		let a = FixedU128::min_value();
+		let b = 0.into();
+		assert!(a.checked_div(&b).is_none());
+	}
+
+	#[test]
+	#[should_panic(expected = "attempt to divide by zero")]
+	fn op_div_zero_should_panic() {
+		let a = FixedU128::max_value();
+		let b = 0.into();
+		let _c = a / b;
+	}
+
+	#[test]
+	fn op_div_works() {
+		let a = FixedU128::saturating_from_rational(1, 2);
+		let b = FixedU128::saturating_from_rational(5, 3);
+		assert_eq!(FixedU128::saturating_from_rational(3, 10), a / b);
+	}
+
+	#[test]
+	fn saturation_from_integer_works() {
+		let inner_max = <FixedU128 as FixedUnsignedNumber>::Inner::max_value();
+		let inner_min = <FixedU128 as FixedUnsignedNumber>::Inner::min_value();
+		let accuracy = FixedU128::accuracy();
+
+		// Cases where integer fits.
+		let a = FixedU128::saturating_from_integer(42);
+		assert_eq!(a.into_inner(), 42 * accuracy);
+
+		// Cases where pass an negative number, should return zero
+		let a = FixedU128::saturating_from_integer(-42);
+		assert_eq!(a.into_inner(), 0);
+
+		// Max/min integers that fit.
+		let a = FixedU128::saturating_from_integer(inner_max / accuracy);
+		assert_eq!(a.into_inner(), (inner_max / accuracy) * accuracy);
+
+		let a = FixedU128::saturating_from_integer(inner_min / accuracy);
+		assert_eq!(a.into_inner(), (inner_min / accuracy) * accuracy);
+
+		// Cases where integer doesn't fit, so it saturates.
+		let a = FixedU128::saturating_from_integer(inner_max / accuracy + 1);
+		assert_eq!(a.into_inner(), inner_max);
+	}
+
+	#[test]
+	fn checked_from_integer_works() {
+		let inner_max = <FixedU128 as FixedUnsignedNumber>::Inner::max_value();
+		let inner_min = <FixedU128 as FixedUnsignedNumber>::Inner::min_value();
+		let accuracy = FixedU128::accuracy();
+
+		// Cases where integer fits.
+		let a = FixedU128::checked_from_integer(42).expect("42 * accuracy < inner_max, qed");
+		assert_eq!(a.into_inner(), 42 * accuracy);
+
+		// Max/min integers that fit.
+		let a = FixedU128::checked_from_integer(inner_max / accuracy).expect("inner_max / accuracy < inner_max, qed");
+		assert_eq!(a.into_inner(), (inner_max / accuracy) * accuracy);
+
+		let a = FixedU128::checked_from_integer(inner_min).expect("inner_min = 0, qed");
+		assert_eq!(a.into_inner(), inner_min);
+
+		// Cases where integer not fit.
+		let a = FixedU128::checked_from_integer(inner_max / accuracy + 1);
+		assert_eq!(a, None);
+	}
+
+	#[test]
+	fn from_inner_works() {
+		let inner_max = <FixedU128 as FixedUnsignedNumber>::Inner::max_value();
+		let inner_min = <FixedU128 as FixedUnsignedNumber>::Inner::min_value();
+		assert_eq!(FixedU128::max_value(), FixedU128::from_inner(inner_max));
+		assert_eq!(FixedU128::min_value(), FixedU128::from_inner(inner_min));
+	}
+
+	#[test]
+	fn saturating_from_ration_works() {
+		let inner_max = <FixedU128 as FixedUnsignedNumber>::Inner::max_value();
+		let inner_min = <FixedU128 as FixedUnsignedNumber>::Inner::min_value();
+		let accuracy = FixedU128::accuracy();
+
+		// Cases where parameters fit.
+		let a = FixedU128::saturating_from_rational(3, 5);
+		assert_eq!(a.into_inner(), 3 * accuracy / 5);
+
+		// Cases where MIX/MIN
+		let a = FixedU128::saturating_from_rational(inner_min, 1);
+		assert_eq!(a.into_inner(), inner_min);
+
+		let a = FixedU128::saturating_from_rational(inner_max, 1);
+		assert_eq!(a.into_inner(), inner_max);
+
+		// Cases where parameters are negative should return zero
+		let a = FixedU128::saturating_from_rational(-1, 1);
+		assert_eq!(a.into_inner(), 0);
+
+		let a = FixedU128::saturating_from_rational(1, -1);
+		assert_eq!(a.into_inner(), 0);
+
+		let a = FixedU128::saturating_from_rational(-3, -5);
+		assert_eq!(a.into_inner(), 0);
+	}
+
+	#[test]
+	#[should_panic(expected = "attempt to divide by zero")]
+	fn saturation_from_ration_with_zero_should_panic() {
+		let _a = FixedU128::saturating_from_rational(100, 0);
+	}
+
+	#[test]
+	fn checked_from_rational_works() {
+		let inner_max = <FixedU128 as FixedUnsignedNumber>::Inner::max_value();
+		let inner_min = <FixedU128 as FixedUnsignedNumber>::Inner::min_value();
+		let accuracy = FixedU128::accuracy();
+
+		let a = FixedU128::checked_from_rational(3, 5).expect("3 * accuracy / 5 < inner_max, qed");
+		assert_eq!(a.into_inner(), 3 * accuracy / 5);
+
+		// Case: limit
+		let a = FixedU128::checked_from_rational(inner_min, 1).expect("inner_min / 1 = inner_min, qed");
+		assert_eq!(a.into_inner(), inner_min);
+
+		let a = FixedU128::saturating_from_rational(inner_max, 1);
+		assert_eq!(a.into_inner(), inner_max);
+
+		let a = FixedU128::checked_from_rational(inner_max / accuracy, 1)
+			.expect("inner_max / accuracy * accuracy < inner_max, qed");
+		assert_eq!(a.into_inner(), inner_max / accuracy * accuracy);
+
+		let a = FixedU128::checked_from_rational(inner_min as i128 - 1, 1);
+		assert_eq!(a, None);
+
+		let a = FixedU128::checked_from_rational(inner_max, 1);
+		assert_eq!(a, None);
+
+		// Cases where parameters are negative should return None
+		let a = FixedU128::checked_from_rational(3, -5);
+		assert_eq!(a, None);
+
+		let a = FixedU128::checked_from_rational(-3, 5);
+		assert_eq!(a, None);
+
+		let a = FixedU128::checked_from_rational(-3, -5);
+		assert_eq!(a, None);
+
+		// Case: divided zero should return None
+		let a = FixedU128::checked_from_rational(10, 0);
+		assert_eq!(a, None);
+	}
+
+	#[test]
+	fn checked_mul_int_works() {
+		let a = FixedU128::saturating_from_rational(10, 1);
+		let b = u32::max_value() / 5;
+		assert_eq!(a.checked_mul_int(b), None);
+
+		let a = FixedU128::saturating_from_integer(120);
+		let b = 2i32;
+		assert_eq!(a.checked_mul_int::<i32>(b), Some(240));
+
+		let a = FixedU128::saturating_from_rational(1, 2);
+		let b = 20i32;
+		assert_eq!(a.checked_mul_int::<i32>(b), Some(10));
+
+		// Case where the integer is negative should return None
+		let a = FixedU128::saturating_from_rational(1, 2);
+		let b = -20i32;
+		assert_eq!(a.checked_mul_int::<i32>(b), None);
 	}
 
 	#[test]
-	fn over_flow_should_be_none() {
-		let a = FixedU128::from_parts(u128::max_value() - 1);
-		let b = FixedU128::from_parts(2);
-		assert_eq!(a.checked_add(&b), None);
+	fn saturating_mul_int_works() {
+		let a = FixedU128::saturating_from_integer(2);
+		// Max - 1.
+		assert_eq!(a.saturating_mul_int((i128::max_value() - 1) / 2), i128::max_value() - 1);
+		// Max
+		assert_eq!(a.saturating_mul_int(i128::max_value() / 2), i128::max_value() - 1);
+		// Max + 1 => saturates to max.
+		assert_eq!(a.saturating_mul_int(i128::max_value() / 2 + 1), i128::max_value());
+
+		let a = FixedU128::saturating_from_rational(1, 2);
+		assert_eq!(a.saturating_mul_int(42i32), 21);
+		assert_eq!(a.saturating_mul_int(i128::max_value()), i128::max_value() / 2);
+
+		// Case: saturating max
+		let c = FixedU128::saturating_from_integer(255);
+		assert_eq!(c.saturating_mul_int(2i8), i8::max_value());
+		assert_eq!(c.saturating_mul_int(i128::max_value()), i128::max_value());
+
+		// Case: negative => 0
+		assert_eq!(a.saturating_mul_int(-2i8), 0i8);
+		assert_eq!(a.saturating_mul_int(i128::min_value()), 0i128);
+	}
 
+	#[test]
+	fn checked_div_int_works() {
+		let inner_max = <FixedU128 as FixedUnsignedNumber>::Inner::max_value();
+		let inner_min = <FixedU128 as FixedUnsignedNumber>::Inner::min_value();
+		let accuracy = FixedU128::accuracy();
+
+		let a = FixedU128::from_inner(inner_max);
+		let b = FixedU128::from_inner(inner_min);
+		let c = FixedU128::zero();
+		let d = FixedU128::one();
+		let e = FixedU128::saturating_from_integer(6);
+		let f = FixedU128::saturating_from_integer(5);
+
+		assert_eq!(e.checked_div_int(2.into()), Some(3));
+		assert_eq!(f.checked_div_int(2.into()), Some(2));
+
+		assert_eq!(a.checked_div_int(i128::max_value()), Some(0));
+		assert_eq!(a.checked_div_int(2), Some(inner_max / (2 * accuracy)));
+		assert_eq!(a.checked_div_int(inner_max / accuracy), Some(1));
+		assert_eq!(a.checked_div_int(1i8), None);
+
+		assert_eq!(b.checked_div_int(2), Some(0));
+		assert_eq!(b.checked_div_int(1i8), Some(0));
+
+		assert_eq!(c.checked_div_int(1), Some(0));
+		assert_eq!(c.checked_div_int(i128::max_value()), Some(0));
+		assert_eq!(c.checked_div_int(1i8), Some(0));
+
+		assert_eq!(d.checked_div_int(1), Some(1));
+		assert_eq!(d.checked_div_int(i32::max_value()), Some(0));
+
+		assert_eq!(d.checked_div_int(1i8), Some(1));
+
+		assert_eq!(a.checked_div_int(0), None);
+		assert_eq!(b.checked_div_int(0), None);
+		assert_eq!(c.checked_div_int(0), None);
+		assert_eq!(d.checked_div_int(0), None);
+	}
+
+	#[test]
+	fn saturating_div_int_works() {
 		let a = FixedU128::max_value();
-		let b = FixedU128::from_rational(2, 1);
-		assert_eq!(a.checked_mul(&b), None);
+		let b = 5u32;
+		assert_eq!(a.saturating_div_int(b), u32::max_value());
+
+		let a = FixedU128::saturating_from_integer(100);
+		let b = 10u8;
+		assert_eq!(a.saturating_div_int(b), 10u8);
+
+		// Case where the integer is negative should return zero
+		let a = FixedU128::saturating_from_integer(100);
+		let b = -10;
+		assert_eq!(a.saturating_div_int(b), 0);
+
+		let a = FixedU128::saturating_from_integer(100);
+		let b = 10;
+		assert_eq!(a.saturating_div_int(b), 10);
+	}
+
+	#[test]
+	fn saturating_mul_acc_int_works() {
+		assert_eq!(FixedU128::zero().saturating_mul_acc_int(42u8), 42u8);
+		assert_eq!(FixedU128::one().saturating_mul_acc_int(42u8), 2 * 42u8);
+
+		assert_eq!(
+			FixedU128::one().saturating_mul_acc_int(i128::max_value()),
+			i128::max_value()
+		);
+		assert_eq!(
+			FixedU128::one().saturating_mul_acc_int(i128::min_value()),
+			i128::min_value()
+		);
+
+		assert_eq!(
+			FixedU128::one().saturating_mul_acc_int(u128::max_value() / 2),
+			u128::max_value() - 1
+		);
+	}
+
+	#[test]
+	fn checked_div_works() {
+		let inner_max = <FixedU128 as FixedUnsignedNumber>::Inner::max_value();
+		let inner_min = <FixedU128 as FixedUnsignedNumber>::Inner::min_value();
+
+		let a = FixedU128::from_inner(inner_max);
+		let b = FixedU128::from_inner(inner_min);
+		let c = FixedU128::zero();
+		let d = FixedU128::one();
+		let e = FixedU128::saturating_from_integer(6);
+		let f = FixedU128::saturating_from_integer(5);
+
+		assert_eq!(e.checked_div(&2.into()), Some(3.into()));
+		assert_eq!(
+			f.checked_div(&2.into()),
+			Some(FixedU128::saturating_from_rational(10, 4))
+		);
+
+		assert_eq!(a.checked_div(&inner_max.into()), Some(1.into()));
+		assert_eq!(a.checked_div(&2.into()), Some(FixedU128::from_inner(inner_max / 2)));
+		assert_eq!(a.checked_div(&FixedU128::max_value()), Some(1.into()));
+		assert_eq!(a.checked_div(&d), Some(a));
+
+		// Cases inner_min is zero
+		assert_eq!(b.checked_div(&b), None);
+
+		assert_eq!(c.checked_div(&1.into()), Some(0.into()));
+		assert_eq!(c.checked_div(&FixedU128::max_value()), Some(0.into()));
+
+		assert_eq!(d.checked_div(&1.into()), Some(1.into()));
+
+		assert_eq!(a.checked_div(&FixedU128::one()), Some(a));
+		assert_eq!(b.checked_div(&FixedU128::one()), Some(b));
+		assert_eq!(c.checked_div(&FixedU128::one()), Some(c));
+		assert_eq!(d.checked_div(&FixedU128::one()), Some(d));
+
+		assert_eq!(a.checked_div(&FixedU128::zero()), None);
+		assert_eq!(b.checked_div(&FixedU128::zero()), None);
+		assert_eq!(c.checked_div(&FixedU128::zero()), None);
+		assert_eq!(d.checked_div(&FixedU128::zero()), None);
+	}
+
+	#[test]
+	fn trunc_works() {
+		let n = FixedU128::saturating_from_rational(5, 2).trunc();
+		assert_eq!(n, FixedU128::saturating_from_integer(2));
+	}
+
+	#[test]
+	fn frac_works() {
+		let n = FixedU128::saturating_from_rational(5, 2);
+		let i = n.trunc();
+		let f = n.frac();
+
+		assert_eq!(n, i + f);
+
+		let n = FixedU128::saturating_from_rational(5, 2)
+			.frac()
+			.saturating_mul(10.into());
+		assert_eq!(n, 5.into());
+
+		let n = FixedU128::saturating_from_rational(1, 2)
+			.frac()
+			.saturating_mul(10.into());
+		assert_eq!(n, 5.into());
+	}
+
+	#[test]
+	fn ceil_works() {
+		let n = FixedU128::saturating_from_rational(5, 2);
+		assert_eq!(n.ceil(), 3.into());
+
+		// On the limits:
+		let n = FixedU128::max_value();
+		assert_eq!(n.ceil(), n.trunc());
+
+		let n = FixedU128::min_value();
+		assert_eq!(n.ceil(), n.trunc());
+	}
+
+	#[test]
+	fn floor_works() {
+		let n = FixedU128::saturating_from_rational(5, 2);
+		assert_eq!(n.floor(), 2.into());
+
+		// On the limits:
+		let n = FixedU128::max_value();
+		assert_eq!(n.floor(), n.trunc());
+
+		let n = FixedU128::min_value();
+		assert_eq!(n.floor(), n.trunc());
+	}
+
+	#[test]
+	fn round_works() {
+		let n = FixedU128::zero();
+		assert_eq!(n.round(), n);
+
+		let n = FixedU128::one();
+		assert_eq!(n.round(), n);
+
+		let n = FixedU128::saturating_from_rational(5, 2);
+		assert_eq!(n.round(), 3.into());
+
+		let n = FixedU128::max_value();
+		assert_eq!(n.round(), n.trunc());
+
+		let n = FixedU128::min_value();
+		assert_eq!(n.round(), n.trunc());
+
+		// On the limit:
+
+		// floor(max - 1) + 0.33..
+		let n = FixedU128::max_value()
+			.saturating_sub(1.into())
+			.trunc()
+			.saturating_add(FixedU128::saturating_from_rational(1, 3));
+
+		assert_eq!(n.round(), (FixedU128::max_value() - 1.into()).trunc());
+
+		// floor(min + 1) - 0.33..
+		let n = FixedU128::min_value()
+			.saturating_add(1.into())
+			.trunc()
+			.saturating_sub(FixedU128::saturating_from_rational(1, 3));
+
+		assert_eq!(n.round(), (FixedU128::min_value() + 1.into()).trunc());
+
+		// floor(max - 1) + 0.6
+		let n = FixedU128::max_value()
+			.saturating_sub(1.into())
+			.trunc()
+			.saturating_add(FixedU128::saturating_from_rational(1, 2));
+
+		assert_eq!(n.round(), FixedU128::max_value().trunc());
 
-		let a = FixedU128::from_natural(255);
-		let b = 2u8;
-		assert_eq!(a.checked_mul_int(&b), None);
+		// floor(min + 1) - 0.6
+		let n = FixedU128::min_value()
+			.saturating_add(1.into())
+			.trunc()
+			.saturating_sub(FixedU128::saturating_from_rational(10, 6));
 
-		let a = FixedU128::from_natural(256);
-		let b = 1u8;
-		assert_eq!(a.checked_div_int(&b), None);
+		assert_eq!(n.round(), FixedU128::min_value().trunc());
 	}
 
 	#[test]
 	fn perthing_into_fixed_u128() {
 		let ten_percent_percent: FixedU128 = Percent::from_percent(10).into();
-		assert_eq!(ten_percent_percent.deconstruct(), DIV / 10);
+		assert_eq!(ten_percent_percent.into_inner(), DIV / 10);
 
 		let ten_percent_permill: FixedU128 = Permill::from_percent(10).into();
-		assert_eq!(ten_percent_permill.deconstruct(), DIV / 10);
+		assert_eq!(ten_percent_permill.into_inner(), DIV / 10);
 
 		let ten_percent_perbill: FixedU128 = Perbill::from_percent(10).into();
-		assert_eq!(ten_percent_perbill.deconstruct(), DIV / 10);
+		assert_eq!(ten_percent_perbill.into_inner(), DIV / 10);
 
 		let ten_percent_perquintill: FixedU128 = Perquintill::from_percent(10).into();
-		assert_eq!(ten_percent_perquintill.deconstruct(), DIV / 10);
+		assert_eq!(ten_percent_perquintill.into_inner(), DIV / 10);
 	}
 
 	#[test]
-	fn recip_should_work() {
+	fn recip_works() {
 		let a = FixedU128::from_natural(2);
-		assert_eq!(a.recip(), Some(FixedU128::from_rational(1, 2)));
+		assert_eq!(a.reciprocal(), Some(FixedU128::saturating_from_rational(1, 2)));
 
 		let a = FixedU128::from_natural(2);
-		assert_eq!(a.recip().unwrap().checked_mul_int(&4i32), Some(2i32));
+		assert_eq!(a.reciprocal().unwrap().checked_mul_int(4i32), Some(2i32));
 
-		let a = FixedU128::from_rational(100, 121);
-		assert_eq!(a.recip(), Some(FixedU128::from_rational(121, 100)));
+		let a = FixedU128::saturating_from_rational(100, 121);
+		assert_eq!(a.reciprocal(), Some(FixedU128::saturating_from_rational(121, 100)));
 
-		let a = FixedU128::from_rational(1, 2);
-		assert_eq!(a.recip().unwrap().checked_mul(&a), Some(FixedU128::from_natural(1)));
+		let a = FixedU128::saturating_from_rational(1, 2);
+		assert_eq!(
+			a.reciprocal().unwrap().checked_mul(&a),
+			Some(FixedU128::from_natural(1))
+		);
 
 		let a = FixedU128::from_natural(0);
-		assert_eq!(a.recip(), None);
+		assert_eq!(a.reciprocal(), None);
 	}
 
 	#[test]
-	fn serialize_deserialize_should_work() {
-		let two_point_five = FixedU128::from_rational(5, 2);
+	fn serialize_deserialize_works() {
+		let two_point_five = FixedU128::saturating_from_rational(5, 2);
 		let serialized = serde_json::to_string(&two_point_five).unwrap();
 		assert_eq!(serialized, "\"2500000000000000000\"");
 		let deserialized: FixedU128 = serde_json::from_str(&serialized).unwrap();
diff --git a/utilities/src/lib.rs b/utilities/src/lib.rs
index 7fb5b28a1d0e8d026c0f1b6375bca70db11d424a..4e8662c9a7b5c324d76348a708bdacd05fdf261a 100644
--- a/utilities/src/lib.rs
+++ b/utilities/src/lib.rs
@@ -5,5 +5,6 @@ pub mod linked_item;
 pub mod ordered_set;
 
 pub use fixed_u128::FixedU128;
+pub use fixed_u128::FixedUnsignedNumber;
 pub use linked_item::{LinkedItem, LinkedList};
 pub use ordered_set::OrderedSet;