use crate::fmt::Formatter;
use crate::types::balance::error;
use crate::types::{EthGas, Fee};
use crate::{format, Add, Display, Mul, Sub, SubAssign, ToString, U256};
use borsh::{io, BorshDeserialize, BorshSerialize};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub const ZERO_NEP141_WEI: NEP141Wei = NEP141Wei::new(0);
pub const ZERO_WEI: Wei = Wei::zero();
pub type WeiU256 = [u8; 32];
#[derive(
Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, BorshSerialize, BorshDeserialize,
)]
pub struct NEP141Wei(u128);
impl Serialize for NEP141Wei {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let value = self.0.to_string();
serializer.serialize_str(&value)
}
}
impl<'de> Deserialize<'de> for NEP141Wei {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
D::Error: serde::de::Error,
{
use serde::de::Error;
let value = serde_json::Value::deserialize(deserializer)?;
Ok(Self(
value
.as_str()
.ok_or_else(|| Error::custom(format!("Wait for a string but got: {value}")))
.and_then(|value| value.parse().map_err(Error::custom))?,
))
}
}
impl Display for NEP141Wei {
fn fmt(&self, f: &mut Formatter<'_>) -> crate::fmt::Result {
self.0.fmt(f)
}
}
impl NEP141Wei {
#[must_use]
pub const fn new(amount: u128) -> Self {
Self(amount)
}
pub fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Self)
}
pub fn checked_add(self, rhs: Self) -> Option<Self> {
self.0.checked_add(rhs.0).map(Self)
}
#[must_use]
pub const fn as_u128(self) -> u128 {
self.0
}
}
impl Sub for NEP141Wei {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0 - rhs.0)
}
}
impl Add for NEP141Wei {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl SubAssign for NEP141Wei {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub struct Wei(U256);
impl Wei {
const ETH_TO_WEI: U256 = U256([1_000_000_000_000_000_000, 0, 0, 0]);
#[must_use]
pub const fn zero() -> Self {
Self(U256::zero())
}
#[must_use]
pub const fn new(amount: U256) -> Self {
Self(amount)
}
#[must_use]
pub const fn new_u64(amount: u64) -> Self {
Self(U256([amount, 0, 0, 0]))
}
#[must_use]
pub fn new_u128(amount: u128) -> Self {
Self::new(U256::from(amount))
}
#[must_use]
pub fn from_eth(amount: U256) -> Option<Self> {
amount.checked_mul(Self::ETH_TO_WEI).map(Self)
}
#[must_use]
pub fn to_bytes(self) -> [u8; 32] {
u256_to_arr(&self.0)
}
#[must_use]
#[allow(clippy::missing_const_for_fn)] pub fn is_zero(&self) -> bool {
self.0.is_zero()
}
#[must_use]
pub const fn raw(self) -> U256 {
self.0
}
pub fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Self)
}
pub fn checked_add(self, rhs: Self) -> Option<Self> {
self.0.checked_add(rhs.0).map(Self)
}
pub fn try_into_u128(self) -> Result<u128, error::BalanceOverflowError> {
self.0.try_into().map_err(|_| error::BalanceOverflowError)
}
}
impl Display for Wei {
fn fmt(&self, f: &mut Formatter<'_>) -> crate::fmt::Result {
self.0.fmt(f)
}
}
impl Add for Wei {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl Sub for Wei {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0 - rhs.0)
}
}
impl Mul<EthGas> for Wei {
type Output = Self;
fn mul(self, rhs: EthGas) -> Self::Output {
Self(self.0 * rhs.as_u256())
}
}
impl From<WeiU256> for Wei {
fn from(value: WeiU256) -> Self {
Self(U256::from_big_endian(&value))
}
}
impl From<Fee> for Wei {
fn from(value: Fee) -> Self {
Self(U256::from(value.as_u128()))
}
}
impl From<NEP141Wei> for Wei {
fn from(value: NEP141Wei) -> Self {
Self(U256::from(value.as_u128()))
}
}
#[allow(dead_code)]
#[must_use]
pub fn u256_to_arr(value: &U256) -> [u8; 32] {
value.to_big_endian()
}
impl BorshSerialize for Wei {
fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
writer.write_all(&self.to_bytes())
}
}
impl BorshDeserialize for Wei {
fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
let mut buf = [0u8; 32];
let maybe_read = reader.read_exact(&mut buf);
if maybe_read.as_ref().err().map(io::Error::kind) == Some(io::ErrorKind::UnexpectedEof) {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Invalid length of the input",
));
}
maybe_read?;
Ok(Self::from(buf))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_wei_from_eth() {
let eth_amount: u64 = rand::random();
let wei_amount = U256::from(eth_amount) * U256::from(10).pow(18.into());
assert_eq!(Wei::from_eth(eth_amount.into()), Some(Wei::new(wei_amount)));
}
#[test]
fn test_wei_from_u64() {
let x: u64 = rand::random();
assert_eq!(Wei::new_u64(x).raw().as_u64(), x);
}
}