Skip to content

Commit

Permalink
add-doc
Browse files Browse the repository at this point in the history
  • Loading branch information
malik672 committed Dec 27, 2023
1 parent e456e1d commit 10e21b7
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 43 deletions.
1 change: 1 addition & 0 deletions src/entities/base_currency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub trait BaseCurrency: Clone {
fn name(&self) -> Option<String>;
}

// Implementation of methods for CurrencyLike
impl<M: Clone> BaseCurrency for CurrencyLike<M> {
fn chain_id(&self) -> u32 {
self.chain_id
Expand Down
13 changes: 12 additions & 1 deletion src/entities/ether.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,36 @@ use alloy_primitives::Address;
use lazy_static::lazy_static;
use std::{collections::HashMap, sync::Mutex};

// Lazy static cache for Ether instances
lazy_static! {
static ref ETHER_CACHE: Mutex<HashMap<u32, Ether>> = Mutex::new(HashMap::new());
}

/// Ether is the main usage of a 'native' currency, i.e. for Ethereum mainnet and all testnets
/// Ether is the main usage of a 'native' currency, i.e., for Ethereum mainnet and all testnets.
/// Represents the native currency with additional metadata.
pub type Ether = CurrencyLike<()>;

/// Implementation of the `CurrencyTrait` for the `Ether` type.
impl CurrencyTrait for Ether {
/// Checks if the currency is native to the blockchain.
fn is_native(&self) -> bool {
true
}

/// Retrieves the address associated with the currency.
fn address(&self) -> Address {
self.wrapped().address()
}

/// Checks if the currency is equal to another currency.
fn equals(&self, other: &impl CurrencyTrait) -> bool {
match other.is_native() {
true => self.chain_id() == other.chain_id(),
_ => false,
}
}

/// Returns the wrapped token representation of the currency.
fn wrapped(&self) -> Token {
match WETH9::default().get(self.chain_id()) {
Some(weth9) => weth9.clone(),
Expand All @@ -39,7 +46,9 @@ impl CurrencyTrait for Ether {
}
}

/// Implementation of additional methods for the `Ether` type.
impl Ether {
/// Creates a new instance of `Ether` with the specified chain ID.
pub fn new(chain_id: u32) -> Self {
Self {
chain_id,
Expand All @@ -50,6 +59,7 @@ impl Ether {
}
}

/// Retrieves or creates an `Ether` instance for the specified chain ID.
pub fn on_chain(chain_id: u32) -> Self {
let mut cache = ETHER_CACHE.lock().unwrap();
match cache.get(&chain_id) {
Expand All @@ -63,6 +73,7 @@ impl Ether {
}
}


#[cfg(test)]
mod tests {
use super::*;
Expand Down
60 changes: 37 additions & 23 deletions src/entities/fractions/currency_amount.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// External crate dependencies
use crate::{
constants::{Rounding, MAX_UINT256},
entities::{
Expand All @@ -11,19 +12,27 @@ use num_integer::Integer;
use rust_decimal::Decimal;
use std::{ops::Div, str::FromStr};

// Type alias for a currency amount using the FractionLike trait
pub type CurrencyAmount<T> = FractionLike<CurrencyMeta<T>>;

// Struct representing metadata about a currency
#[derive(Clone, PartialEq)]
pub struct CurrencyMeta<T: CurrencyTrait> {
pub currency: T,
pub decimal_scale: BigUint,
}

// Implementation of methods for CurrencyAmount
impl<T: CurrencyTrait> CurrencyAmount<T> {
// Constructor method for creating a new currency amount
fn new(currency: T, numerator: impl Into<BigInt>, denominator: impl Into<BigInt>) -> Self {
let numerator = numerator.into();
let denominator = denominator.into();
assert!(numerator.div_floor(&denominator).le(&MAX_UINT256), "AMOUNT");
// Ensure the amount does not exceed MAX_UINT256
assert!(
numerator.div_floor(&denominator).le(&MAX_UINT256),
"AMOUNT"
);
let exponent = currency.decimals();
FractionTrait::new(
numerator,
Expand All @@ -35,29 +44,12 @@ impl<T: CurrencyTrait> CurrencyAmount<T> {
)
}

/// Returns a new currency amount instance from the unitless amount of token, i.e. the raw amount
///
/// # Arguments
///
/// * `currency`: the currency in the amount
/// * `raw_amount`: the raw token or ether amount
///
/// returns: CurrencyAmount
///
// Returns a new currency amount instance from the unitless amount of token (raw amount)
pub fn from_raw_amount(currency: T, raw_amount: impl Into<BigInt>) -> CurrencyAmount<T> {
Self::new(currency, raw_amount, 1)
}

/// Construct a currency amount with a denominator that is not equal to 1
///
/// # Arguments
///
/// * `currency`: the currency
/// * `numerator`: the numerator of the fractional token amount
/// * `denominator`: the denominator of the fractional token amount
///
/// returns: CurrencyAmount
///
// Construct a currency amount with a denominator that is not equal to 1
pub fn from_fractional_amount(
currency: T,
numerator: impl Into<BigInt>,
Expand All @@ -66,6 +58,7 @@ impl<T: CurrencyTrait> CurrencyAmount<T> {
Self::new(currency, numerator, denominator)
}

// Multiplication of currency amount by another fractional amount
pub fn multiply<M>(&self, other: &impl FractionTrait<M>) -> Self {
let multiplied = self.as_fraction().multiply(&other.as_fraction());
Self::from_fractional_amount(
Expand All @@ -75,6 +68,7 @@ impl<T: CurrencyTrait> CurrencyAmount<T> {
)
}

// Division of currency amount by another fractional amount
pub fn divide<M>(&self, other: &impl FractionTrait<M>) -> Self {
let divided = self.as_fraction().divide(&other.as_fraction());
Self::from_fractional_amount(
Expand All @@ -84,15 +78,20 @@ impl<T: CurrencyTrait> CurrencyAmount<T> {
)
}

// Convert the currency amount to a string with exact precision
pub fn to_exact(&self) -> String {
Decimal::from_str(&self.quotient().to_str_radix(10))
.unwrap()
.div(Decimal::from_str(&self.meta.decimal_scale.to_str_radix(10)).unwrap())
.to_string()
}

// Addition of another currency amount to the current amount
pub fn add(&self, other: &Self) -> Self {
assert!(self.meta.currency.equals(&other.meta.currency), "CURRENCY");
assert!(
self.meta.currency.equals(&other.meta.currency),
"CURRENCY"
);
let added = self.as_fraction().add(&other.as_fraction());
Self::from_fractional_amount(
self.meta.currency.clone(),
Expand All @@ -101,8 +100,12 @@ impl<T: CurrencyTrait> CurrencyAmount<T> {
)
}

// Subtraction of another currency amount from the current amount
pub fn subtract(&self, other: &Self) -> Self {
assert!(self.meta.currency.equals(&other.meta.currency), "CURRENCY");
assert!(
self.meta.currency.equals(&other.meta.currency),
"CURRENCY"
);
let subtracted = self.as_fraction().subtract(&other.as_fraction());
Self::from_fractional_amount(
self.meta.currency.clone(),
Expand All @@ -111,21 +114,28 @@ impl<T: CurrencyTrait> CurrencyAmount<T> {
)
}

// Convert the currency amount to a string with a specified number of significant digits
pub fn to_significant(&self, significant_digits: u8, rounding: Rounding) -> String {
self.as_fraction()
.divide(&Fraction::new(self.meta.decimal_scale.clone(), 1))
.to_significant(significant_digits, rounding)
}

// Convert the currency amount to a string with a fixed number of decimal places
pub fn to_fixed(&self, decimal_places: u8, rounding: Rounding) -> String {
assert!(decimal_places <= self.meta.currency.decimals(), "DECIMALS");
assert!(
decimal_places <= self.meta.currency.decimals(),
"DECIMALS"
);
self.as_fraction()
.divide(&Fraction::new(self.meta.decimal_scale.clone(), 1))
.to_fixed(decimal_places, rounding)
}
}

// Implementation for a specific type of CurrencyAmount (Token)
impl CurrencyAmount<Token> {
// Wrap the currency amount if the currency is not native
pub fn wrapped(&self) -> CurrencyAmount<Token> {
match &self.meta.currency.is_native() {
true => Self::from_fractional_amount(
Expand All @@ -138,6 +148,7 @@ impl CurrencyAmount<Token> {
}
}

// Unit tests for the currency module
#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -146,8 +157,10 @@ mod tests {
};
use lazy_static::lazy_static;

// Constants for testing
const ADDRESS_ONE: &str = "0x0000000000000000000000000000000000000001";

// Lazy static variables for testing currencies
lazy_static! {
static ref TOKEN18: Currency = Currency::Token(Token::new(
1,
Expand All @@ -169,6 +182,7 @@ mod tests {
));
}

// Unit tests
#[test]
fn test_constructor() {
let amount = CurrencyAmount::from_raw_amount(TOKEN18.clone(), 100);
Expand Down
Loading

0 comments on commit 10e21b7

Please sign in to comment.