fix: switch between units correctly (#170)

This commit is contained in:
Georgios Konstantopoulos 2021-01-17 14:10:30 +02:00 committed by GitHub
parent b19f8f3c14
commit 0b9375688e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 81 additions and 6 deletions

View File

@ -20,6 +20,9 @@ pub use solc::{CompiledContract, Solc};
mod hash; mod hash;
pub use hash::{hash_message, id, keccak256, serialize}; pub use hash::{hash_message, id, keccak256, serialize};
mod units;
pub use units::Units;
/// Re-export RLP /// Re-export RLP
pub use rlp; pub use rlp;
@ -38,9 +41,11 @@ pub fn format_ether<T: Into<U256>>(amount: T) -> U256 {
amount.into() / WEI_IN_ETHER amount.into() / WEI_IN_ETHER
} }
/// Divides with the number of decimals /// Divides the provided amount with 10^{units} provided.
pub fn format_units<T: Into<U256>>(amount: T, decimals: usize) -> U256 { pub fn format_units<T: Into<U256>, K: Into<Units>>(amount: T, units: K) -> U256 {
amount.into() / decimals let units = units.into();
let amount = amount.into();
amount / 10u64.pow(units.as_num())
} }
/// Converts the input to a U256 and converts from Ether to Wei. /// Converts the input to a U256 and converts from Ether to Wei.
@ -59,12 +64,13 @@ where
Ok(eth.try_into()? * WEI_IN_ETHER) Ok(eth.try_into()? * WEI_IN_ETHER)
} }
/// Multiplies with the number of decimals /// Multiplies the provided amount with 10^{units} provided.
pub fn parse_units<S>(eth: S, decimals: usize) -> Result<U256, S::Error> pub fn parse_units<S, K>(amount: S, units: K) -> Result<U256, S::Error>
where where
S: TryInto<U256>, S: TryInto<U256>,
K: Into<Units>,
{ {
Ok(eth.try_into()? * decimals) Ok(amount.try_into()? * 10u64.pow(units.into().as_num()))
} }
/// The address for an Ethereum contract is deterministically computed from the /// The address for an Ethereum contract is deterministically computed from the
@ -166,6 +172,24 @@ mod tests {
assert_eq!(WEI_IN_ETHER.as_u64(), 1e18 as u64); assert_eq!(WEI_IN_ETHER.as_u64(), 1e18 as u64);
} }
#[test]
fn test_format_units() {
let gwei_in_ether = format_units(WEI_IN_ETHER, 9);
assert_eq!(gwei_in_ether.as_u64(), 1e9 as u64);
let eth = format_units(WEI_IN_ETHER, "ether");
assert_eq!(eth.as_u64(), 1);
}
#[test]
fn test_parse_units() {
let gwei = parse_units(1, 9).unwrap();
assert_eq!(gwei.as_u64(), 1e9 as u64);
let eth = parse_units(1, "ether").unwrap();
assert_eq!(eth, WEI_IN_ETHER);
}
#[test] #[test]
fn addr_checksum() { fn addr_checksum() {
let addr_list = vec![ let addr_list = vec![

View File

@ -0,0 +1,51 @@
/// Common Ethereum unit types.
pub enum Units {
/// Ether corresponds to 1e18 Wei
Ether,
/// Gwei corresponds to 1e9 Wei
Gwei,
/// Wei corresponds to 1 Wei
Wei,
/// Use this for other less frequent unit sizes
Other(u32),
}
impl Units {
pub fn as_num(&self) -> u32 {
match self {
Units::Ether => 18,
Units::Gwei => 9,
Units::Wei => 1,
Units::Other(inner) => *inner,
}
}
}
impl From<u32> for Units {
fn from(src: u32) -> Self {
Units::Other(src)
}
}
impl From<i32> for Units {
fn from(src: i32) -> Self {
Units::Other(src as u32)
}
}
impl From<usize> for Units {
fn from(src: usize) -> Self {
Units::Other(src as u32)
}
}
impl From<&str> for Units {
fn from(src: &str) -> Self {
match src.to_lowercase().as_str() {
"ether" => Units::Ether,
"gwei" => Units::Gwei,
"wei" => Units::Wei,
_ => panic!("unrecognized units"),
}
}
}