Coin and denom tests
This commit is contained in:
@@ -9,23 +9,25 @@ use cosmwasm_std::Uint128;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Add;
|
use std::ops::{Add, Sub};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use ts_rs::TS;
|
use ts_rs::TS;
|
||||||
use validator_client::nymd::GasPrice;
|
use validator_client::nymd::GasPrice;
|
||||||
|
|
||||||
use crate::format_err;
|
use crate::format_err;
|
||||||
|
|
||||||
#[derive(TS, Serialize, Deserialize, Clone)]
|
#[derive(TS, Serialize, Deserialize, Clone, PartialEq, Debug)]
|
||||||
pub enum Denom {
|
pub enum Denom {
|
||||||
Major,
|
Major,
|
||||||
Minor,
|
Minor,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MINOR_IN_MAJOR: f64 = 1_000_000.;
|
||||||
|
|
||||||
impl fmt::Display for Denom {
|
impl fmt::Display for Denom {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Denom::Major => f.write_str(&DENOM[1..].to_uppercase()),
|
Denom::Major => f.write_str(&DENOM[1..]),
|
||||||
Denom::Minor => f.write_str(DENOM),
|
Denom::Minor => f.write_str(DENOM),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,7 +51,7 @@ impl FromStr for Denom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(TS, Serialize, Deserialize, Clone)]
|
#[derive(TS, Serialize, Deserialize, Clone, PartialEq, Debug)]
|
||||||
pub struct Coin {
|
pub struct Coin {
|
||||||
amount: String,
|
amount: String,
|
||||||
denom: Denom,
|
denom: Denom,
|
||||||
@@ -93,12 +95,55 @@ impl Add for Coin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allows adding minor and major denominations, output will have the LHS denom.
|
||||||
|
impl Sub for Coin {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self {
|
||||||
|
let denom = self.denom.clone();
|
||||||
|
let lhs = self.to_minor();
|
||||||
|
let rhs = rhs.to_minor();
|
||||||
|
let lhs_amount = lhs.amount.parse::<i64>().unwrap();
|
||||||
|
let rhs_amount = rhs.amount.parse::<i64>().unwrap();
|
||||||
|
let amount = lhs_amount - rhs_amount;
|
||||||
|
let coin = Coin {
|
||||||
|
amount: amount.to_string(),
|
||||||
|
denom: Denom::Minor,
|
||||||
|
};
|
||||||
|
match denom {
|
||||||
|
Denom::Major => coin.to_major(),
|
||||||
|
Denom::Minor => coin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Coin {
|
impl Coin {
|
||||||
|
pub fn major<T: ToString>(amount: T) -> Coin {
|
||||||
|
Coin {
|
||||||
|
amount: amount.to_string(),
|
||||||
|
denom: Denom::Major,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn minor<T: ToString>(amount: T) -> Coin {
|
||||||
|
Coin {
|
||||||
|
amount: amount.to_string(),
|
||||||
|
denom: Denom::Minor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new<T: ToString>(amount: T, denom: &Denom) -> Coin {
|
||||||
|
Coin {
|
||||||
|
amount: amount.to_string(),
|
||||||
|
denom: denom.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_major(&self) -> Coin {
|
pub fn to_major(&self) -> Coin {
|
||||||
match self.denom {
|
match self.denom {
|
||||||
Denom::Major => self.clone(),
|
Denom::Major => self.clone(),
|
||||||
Denom::Minor => Coin {
|
Denom::Minor => Coin {
|
||||||
amount: (self.amount.parse::<f64>().unwrap() / 1_000_000.).to_string(),
|
amount: (self.amount.parse::<f64>().unwrap() / MINOR_IN_MAJOR).to_string(),
|
||||||
denom: Denom::Major,
|
denom: Denom::Major,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -108,7 +153,7 @@ impl Coin {
|
|||||||
match self.denom {
|
match self.denom {
|
||||||
Denom::Minor => self.clone(),
|
Denom::Minor => self.clone(),
|
||||||
Denom::Major => Coin {
|
Denom::Major => Coin {
|
||||||
amount: (self.amount.parse::<f64>().unwrap() * 1_000_000.).to_string(),
|
amount: (self.amount.parse::<f64>().unwrap() * MINOR_IN_MAJOR).to_string(),
|
||||||
denom: Denom::Minor,
|
denom: Denom::Minor,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -121,20 +166,12 @@ impl Coin {
|
|||||||
pub fn denom(&self) -> Denom {
|
pub fn denom(&self) -> Denom {
|
||||||
self.denom.clone()
|
self.denom.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(amount: &str, denom: &Denom) -> Coin {
|
|
||||||
Coin {
|
|
||||||
amount: amount.to_string(),
|
|
||||||
denom: denom.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Coin> for CosmWasmCoin {
|
impl TryFrom<Coin> for CosmWasmCoin {
|
||||||
type Error = String;
|
type Error = String;
|
||||||
|
|
||||||
fn try_from(coin: Coin) -> Result<CosmWasmCoin, String> {
|
fn try_from(coin: Coin) -> Result<CosmWasmCoin, String> {
|
||||||
let coin = coin.to_minor();
|
|
||||||
Ok(CosmWasmCoin::new(
|
Ok(CosmWasmCoin::new(
|
||||||
Uint128::try_from(coin.amount.as_str()).unwrap().u128(),
|
Uint128::try_from(coin.amount.as_str()).unwrap().u128(),
|
||||||
coin.denom.to_string(),
|
coin.denom.to_string(),
|
||||||
@@ -146,7 +183,6 @@ impl TryFrom<Coin> for CosmosCoin {
|
|||||||
type Error = String;
|
type Error = String;
|
||||||
|
|
||||||
fn try_from(coin: Coin) -> Result<CosmosCoin, String> {
|
fn try_from(coin: Coin) -> Result<CosmosCoin, String> {
|
||||||
let coin = coin.to_minor();
|
|
||||||
match Decimal::from_str(&coin.amount) {
|
match Decimal::from_str(&coin.amount) {
|
||||||
Ok(d) => Ok(CosmosCoin {
|
Ok(d) => Ok(CosmosCoin {
|
||||||
amount: d,
|
amount: d,
|
||||||
@@ -174,3 +210,141 @@ impl From<CosmWasmCoin> for Coin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::{Coin, Denom};
|
||||||
|
use cosmos_sdk::Coin as CosmosCoin;
|
||||||
|
use cosmos_sdk::Decimal;
|
||||||
|
use cosmos_sdk::Denom as CosmosDenom;
|
||||||
|
use cosmwasm_std::Coin as CosmWasmCoin;
|
||||||
|
use serde_json::json;
|
||||||
|
use std::convert::{TryFrom, TryInto};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn json_to_coin() {
|
||||||
|
let minor = json!({
|
||||||
|
"amount": "1",
|
||||||
|
"denom": "Minor"
|
||||||
|
});
|
||||||
|
|
||||||
|
let major = json!({
|
||||||
|
"amount": "1",
|
||||||
|
"denom": "Major"
|
||||||
|
});
|
||||||
|
|
||||||
|
let test_minor_coin = Coin::minor("1");
|
||||||
|
let test_major_coin = Coin::major("1");
|
||||||
|
|
||||||
|
let minor_coin = serde_json::from_value::<Coin>(minor).unwrap();
|
||||||
|
let major_coin = serde_json::from_value::<Coin>(major).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(minor_coin, test_minor_coin);
|
||||||
|
assert_eq!(major_coin, test_major_coin);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn denom_conversions() {
|
||||||
|
let minor = Coin::minor("1");
|
||||||
|
let major = minor.to_major();
|
||||||
|
|
||||||
|
assert_eq!(major, Coin::major("0.000001"));
|
||||||
|
|
||||||
|
let minor = major.to_minor();
|
||||||
|
assert_eq!(minor, Coin::minor("1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn amounts() -> Vec<&'static str> {
|
||||||
|
vec![
|
||||||
|
"1",
|
||||||
|
"10",
|
||||||
|
"100",
|
||||||
|
"1000",
|
||||||
|
"10000",
|
||||||
|
"100000",
|
||||||
|
"10000000",
|
||||||
|
"100000000",
|
||||||
|
"1000000000",
|
||||||
|
"10000000000",
|
||||||
|
"100000000000",
|
||||||
|
"1000000000000",
|
||||||
|
"10000000000000",
|
||||||
|
"100000000000000",
|
||||||
|
"1000000000000000",
|
||||||
|
"10000000000000000",
|
||||||
|
"100000000000000000",
|
||||||
|
"1000000000000000000"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn coin_to_cosmoswasm() {
|
||||||
|
for amount in amounts() {
|
||||||
|
let coin: Coin = Coin::minor(amount).into();
|
||||||
|
let cosmoswasm_coin: CosmWasmCoin = coin.try_into().unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
cosmoswasm_coin,
|
||||||
|
CosmWasmCoin::new(amount.parse::<u128>().unwrap(), Denom::Minor.to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Coin::try_from(cosmoswasm_coin).unwrap(),
|
||||||
|
Coin::minor(amount)
|
||||||
|
);
|
||||||
|
|
||||||
|
let coin: Coin = Coin::major(amount).into();
|
||||||
|
let cosmoswasm_coin: CosmWasmCoin = coin.try_into().unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
cosmoswasm_coin,
|
||||||
|
CosmWasmCoin::new(amount.parse::<u128>().unwrap(), Denom::Major.to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Coin::try_from(cosmoswasm_coin).unwrap(),
|
||||||
|
Coin::major(amount)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn coin_to_cosmos() {
|
||||||
|
for amount in amounts() {
|
||||||
|
let coin: Coin = Coin::minor(amount).into();
|
||||||
|
let cosmos_coin: CosmosCoin = coin.try_into().unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
cosmos_coin,
|
||||||
|
CosmosCoin {
|
||||||
|
amount: Decimal::from_str(amount).unwrap(),
|
||||||
|
denom: CosmosDenom::from_str(&Denom::Minor.to_string()).unwrap()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(Coin::try_from(cosmos_coin).unwrap(), Coin::minor(amount));
|
||||||
|
|
||||||
|
let coin: Coin = Coin::major(amount).into();
|
||||||
|
let cosmos_coin: CosmosCoin = coin.try_into().unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
cosmos_coin,
|
||||||
|
CosmosCoin {
|
||||||
|
amount: Decimal::from_str(amount).unwrap(),
|
||||||
|
denom: CosmosDenom::from_str(&Denom::Major.to_string()).unwrap()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(Coin::try_from(cosmos_coin).unwrap(), Coin::major(amount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_add() {
|
||||||
|
assert_eq!(Coin::minor("1") + Coin::minor("1"), Coin::minor("2"));
|
||||||
|
assert_eq!(Coin::major("1") + Coin::major("1"), Coin::major("2"));
|
||||||
|
assert_eq!(Coin::minor("1") + Coin::major("1"), Coin::minor("1000001"));
|
||||||
|
assert_eq!(Coin::major("1") + Coin::minor("1"), Coin::major("1.000001"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sub() {
|
||||||
|
assert_eq!(Coin::minor("1") - Coin::minor("1"), Coin::minor("0"));
|
||||||
|
assert_eq!(Coin::major("1") - Coin::major("1"), Coin::major("0"));
|
||||||
|
assert_eq!(Coin::minor("1") - Coin::major("1"), Coin::minor("-999999"));
|
||||||
|
assert_eq!(Coin::major("1") - Coin::minor("1"), Coin::major("0.999999"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user