From fd228d3e9cd2a73981ff62d1a0e2fabab46cb1c7 Mon Sep 17 00:00:00 2001 From: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com> Date: Sun, 5 Jan 2025 03:53:45 -0500 Subject: [PATCH 1/2] perf!: refactor types and replace `num-bigint` with `fastnum` Replace `num-bigint` and `bigdecimal` with `fastnum` for improved performance and simplified arithmetic operations. Updated `Cargo.toml`, core types, and utility functions to utilize `fastnum`'s features and refined the API for consistency. This commits also includes enhancements in test cases and clean-ups for derived constants and methods. --- Cargo.toml | 9 ++- README.md | 2 +- src/constants.rs | 9 +-- src/entities/fractions/currency_amount.rs | 34 +++++----- src/entities/fractions/fraction.rs | 73 ++++++++++----------- src/entities/fractions/price.rs | 9 +-- src/entities/token.rs | 34 +++++----- src/examples/token_example.rs | 4 +- src/lib.rs | 8 +-- src/utils/compute_zksync_create2_address.rs | 2 +- src/utils/mod.rs | 2 + src/utils/sqrt.rs | 34 ++++++---- src/utils/types.rs | 21 ++++++ 13 files changed, 131 insertions(+), 110 deletions(-) create mode 100644 src/utils/types.rs diff --git a/Cargo.toml b/Cargo.toml index 803b62c..f4cbe42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uniswap-sdk-core" -version = "3.3.0" +version = "4.0.0-rc" edition = "2021" authors = ["malik ", "Shuhui Luo "] description = "The Uniswap SDK Core in Rust provides essential functionality for interacting with the Uniswap decentralized exchange" @@ -8,17 +8,16 @@ license = "MIT" [dependencies] alloy-primitives = { version = ">=0.8.5", features = ["map-fxhash"] } -bigdecimal = "0.4.5" derive_more = { version = "1.0.0", features = ["deref"] } eth_checksum = { version = "0.1.2", optional = true } +fastnum = { version = "0.1.9", default-features = false, features = ["libm"] } lazy_static = "1.5" -num-bigint = "0.4" -num-integer = "0.1" regex = { version = "1.11", optional = true } thiserror = { version = "2", default-features = false } [features] -std = ["thiserror/std"] +default = [] +std = ["fastnum/std", "thiserror/std"] validate_parse_address = ["eth_checksum", "regex"] [lib] diff --git a/README.md b/README.md index ce76b93..0572963 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Add this to your Cargo.toml ``` [dependencies] -uniswap-sdk-core = "3.3.0" +uniswap-sdk-core = "4.0.0" ``` And this to your code: diff --git a/src/constants.rs b/src/constants.rs index dbce0a3..6078309 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,7 +1,5 @@ use crate::prelude::*; use alloy_primitives::U256; -use lazy_static::lazy_static; -use num_bigint::Sign; /// Represents the various types of trades. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] @@ -27,8 +25,5 @@ pub enum Rounding { RoundUp, } -lazy_static! { - /// Represents the maximum amount contained in a uint256 - pub static ref MAX_UINT256: BigInt = - BigInt::from_biguint(Sign::Plus, BigUint::from_bytes_le(&U256::MAX.as_le_bytes())); -} +/// Represents the maximum amount contained in a uint256 +pub const MAX_UINT256: BigInt = to_big_int(U256::MAX); diff --git a/src/entities/fractions/currency_amount.rs b/src/entities/fractions/currency_amount.rs index 06a553c..ef9d325 100644 --- a/src/entities/fractions/currency_amount.rs +++ b/src/entities/fractions/currency_amount.rs @@ -1,7 +1,6 @@ use crate::prelude::*; use alloc::string::ToString; -use core::ops::Div; -use num_integer::Integer; +use fastnum::i512; /// Currency amount struct that represents a rational amount of a currency pub type CurrencyAmount = FractionLike>; @@ -12,7 +11,7 @@ pub struct CurrencyMeta { /// The currency associated with this metadata pub currency: T, /// The scale factor for the currency's decimal places - pub decimal_scale: BigUint, + pub decimal_scale: BigInt, } impl CurrencyAmount { @@ -26,7 +25,7 @@ impl CurrencyAmount { let numerator = numerator.into(); let denominator = denominator.into(); // Ensure the amount does not exceed MAX_UINT256 - if numerator.div_floor(&denominator) > *MAX_UINT256 { + if numerator.div_floor(denominator) > MAX_UINT256 { return Err(Error::UintOverflow); } let exponent = currency.decimals(); @@ -35,7 +34,7 @@ impl CurrencyAmount { denominator, CurrencyMeta { currency, - decimal_scale: BigUint::from(10_u64).pow(exponent as u32), + decimal_scale: i512!(10).pow(exponent as u32), }, )) } @@ -81,8 +80,8 @@ impl CurrencyAmount { /// Convert the currency amount to a string with exact precision #[inline] pub fn to_exact(&self) -> String { - BigDecimal::from(self.quotient()) - .div(BigDecimal::from(BigInt::from(self.decimal_scale.clone()))) + to_big_decimal(self.quotient()) + .div(to_big_decimal(self.decimal_scale)) .to_string() } @@ -117,7 +116,7 @@ impl CurrencyAmount { significant_digits: u8, rounding: Option, ) -> Result { - (self.as_fraction() / Fraction::new(self.decimal_scale.clone(), 1)).to_significant( + (self.as_fraction() / Fraction::new(self.decimal_scale, 1)).to_significant( significant_digits, Some(rounding.unwrap_or(Rounding::RoundDown)), ) @@ -134,7 +133,7 @@ impl CurrencyAmount { return Err(Error::Invalid("DECIMALS")); } Ok( - (self.as_fraction() / Fraction::new(self.decimal_scale.clone(), 1)).to_fixed( + (self.as_fraction() / Fraction::new(self.decimal_scale, 1)).to_fixed( decimal_places, Some(rounding.unwrap_or(Rounding::RoundDown)), ), @@ -146,8 +145,8 @@ impl CurrencyAmount { pub fn wrapped(&self) -> Result, Error> { CurrencyAmount::from_fractional_amount( self.currency.wrapped(), - self.numerator().clone(), - self.denominator().clone(), + self.numerator(), + self.denominator(), ) } } @@ -193,31 +192,30 @@ mod tests { #[test] fn test_token_amount_max_uint256() { - let amount = CurrencyAmount::from_raw_amount(TOKEN18.clone(), MAX_UINT256.clone()).unwrap(); + let amount = CurrencyAmount::from_raw_amount(TOKEN18.clone(), MAX_UINT256).unwrap(); assert_eq!(amount.quotient(), MAX_UINT256.clone()); } #[test] #[should_panic(expected = "AMOUNT")] fn test_token_amount_exceeds_max_uint256() { - let _w = CurrencyAmount::from_raw_amount(TOKEN18.clone(), MAX_UINT256.clone() + 1); + let _w = CurrencyAmount::from_raw_amount(TOKEN18.clone(), MAX_UINT256 + BigInt::from(1)); assert!(_w.is_ok(), "AMOUNT"); } #[test] #[should_panic(expected = "AMOUNT")] fn test_token_amount_quotient_exceeds_max_uint256() { - let numerator: BigInt = (MAX_UINT256.clone() + 1) * 2; + let numerator: BigInt = (MAX_UINT256 + BigInt::from(1)) * BigInt::from(2); let _w = CurrencyAmount::from_fractional_amount(TOKEN18.clone(), numerator, 2); assert!(_w.is_ok(), "AMOUNT"); } #[test] fn test_token_amount_numerator_gt_uint256() { - let numerator: BigInt = MAX_UINT256.clone() + 2; - let amount = - CurrencyAmount::from_fractional_amount(TOKEN18.clone(), numerator.clone(), 2).unwrap(); - assert_eq!(amount.numerator(), &numerator); + let numerator: BigInt = MAX_UINT256 + BigInt::from(2); + let amount = CurrencyAmount::from_fractional_amount(TOKEN18.clone(), numerator, 2).unwrap(); + assert_eq!(amount.numerator(), numerator); } #[test] diff --git a/src/entities/fractions/fraction.rs b/src/entities/fractions/fraction.rs index 25b7166..2d9c4f4 100644 --- a/src/entities/fractions/fraction.rs +++ b/src/entities/fractions/fraction.rs @@ -3,11 +3,10 @@ use alloc::string::ToString; use core::{ cmp::Ordering, hash::{Hash, Hasher}, - num::NonZeroU64, ops::{Add, Div, Mul, Sub}, }; use derive_more::Deref; -use num_integer::Integer; +use fastnum::i512; /// Struct representing a fraction with metadata #[derive(Clone, Debug, Deref)] @@ -24,7 +23,7 @@ impl Default for FractionLike { fn default() -> Self { Self { numerator: BigInt::ZERO, - denominator: BigInt::from(1), + denominator: i512!(1), meta: M::default(), } } @@ -85,10 +84,10 @@ pub trait FractionBase: Sized { fn meta(&self) -> &M; /// Accessor method for retrieving numerator - fn numerator(&self) -> &BigInt; + fn numerator(&self) -> BigInt; /// Accessor method for retrieving the denominator - fn denominator(&self) -> &BigInt; + fn denominator(&self) -> BigInt; /// Returns the floor division quotient of the fraction #[inline] @@ -101,7 +100,7 @@ pub trait FractionBase: Sized { fn remainder(&self) -> Self { Self::new( self.numerator() % self.denominator(), - self.denominator().clone(), + self.denominator(), self.meta().clone(), ) } @@ -109,17 +108,13 @@ pub trait FractionBase: Sized { /// Returns the inverted fraction #[inline] fn invert(&self) -> Self { - Self::new( - self.denominator().clone(), - self.numerator().clone(), - self.meta().clone(), - ) + Self::new(self.denominator(), self.numerator(), self.meta().clone()) } /// Converts the fraction to a [`BigDecimal`] #[inline] fn to_decimal(&self) -> BigDecimal { - BigDecimal::from(self.numerator().clone()).div(BigDecimal::from(self.denominator().clone())) + to_big_decimal(self.numerator()) / to_big_decimal(self.denominator()) } /// Converts the fraction to a string with a specified number of significant digits and rounding @@ -134,12 +129,13 @@ pub trait FractionBase: Sized { return Err(Error::Invalid("SIGNIFICANT_DIGITS")); } let rounding_strategy = to_rounding_strategy(rounding.unwrap_or_default()); - let quotient = self.to_decimal().with_precision_round( - NonZeroU64::new(significant_digits as u64).unwrap(), - rounding_strategy, - ); + let quotient = self.to_decimal().with_rounding_mode(rounding_strategy); + let integer_digits = quotient.digits_count() as i16 - quotient.fractional_digits_count(); + let quotient = quotient + .round(significant_digits as i16 - integer_digits) + .reduce(); - Ok(quotient.normalized().to_string()) + Ok(quotient.to_string()) } /// Converts the fraction to a string with a fixed number of decimal places and rounding @@ -148,14 +144,15 @@ pub trait FractionBase: Sized { fn to_fixed(&self, decimal_places: u8, rounding: Option) -> String { let rounding_strategy = to_rounding_strategy(rounding.unwrap_or_default()); self.to_decimal() - .with_scale_round(decimal_places as i64, rounding_strategy) + .with_rounding_mode(rounding_strategy) + .round(decimal_places as i16) .to_string() } /// Helper method for converting any superclass back to a simple [`Fraction`] #[inline] fn as_fraction(&self) -> Fraction { - Fraction::new(self.numerator().clone(), self.denominator().clone()) + Fraction::new(self.numerator(), self.denominator()) } } @@ -182,14 +179,14 @@ impl FractionBase for FractionLike { /// Accessor method for retrieving the numerator #[inline] - fn numerator(&self) -> &BigInt { - &self.numerator + fn numerator(&self) -> BigInt { + self.numerator } /// Accessor method for retrieving the denominator #[inline] - fn denominator(&self) -> &BigInt { - &self.denominator + fn denominator(&self) -> BigInt { + self.denominator } } @@ -197,7 +194,7 @@ impl PartialEq for FractionLike { /// Checks if the current fraction is equal to another fraction #[inline] fn eq(&self, other: &Self) -> bool { - &self.numerator * &other.denominator == &other.numerator * &self.denominator + self.numerator * other.denominator == other.numerator * self.denominator && self.meta == other.meta } } @@ -217,7 +214,7 @@ impl Hash for FractionLike { impl Ord for FractionLike { #[inline] fn cmp(&self, other: &Self) -> Ordering { - (&self.numerator * &other.denominator).cmp(&(&other.numerator * &self.denominator)) + (self.numerator * other.denominator).cmp(&(other.numerator * self.denominator)) } } @@ -241,7 +238,7 @@ impl Add for FractionLike { ) } else { FractionBase::new( - self.numerator * &other.denominator + other.numerator * &self.denominator, + self.numerator * other.denominator + other.numerator * self.denominator, self.denominator * other.denominator, self.meta, ) @@ -256,14 +253,14 @@ impl Add<&Self> for FractionLike { fn add(self, other: &Self) -> Self::Output { if self.denominator == other.denominator { FractionBase::new( - self.numerator + &other.numerator, + self.numerator + other.numerator, self.denominator, self.meta, ) } else { FractionBase::new( - self.numerator * &other.denominator + &other.numerator * &self.denominator, - self.denominator * &other.denominator, + self.numerator * other.denominator + other.numerator * self.denominator, + self.denominator * other.denominator, self.meta, ) } @@ -283,7 +280,7 @@ impl Sub for FractionLike { ) } else { FractionBase::new( - self.numerator * &other.denominator - other.numerator * &self.denominator, + self.numerator * other.denominator - other.numerator * self.denominator, self.denominator * other.denominator, self.meta, ) @@ -298,14 +295,14 @@ impl Sub<&Self> for FractionLike { fn sub(self, other: &Self) -> Self::Output { if self.denominator == other.denominator { FractionBase::new( - self.numerator - &other.numerator, + self.numerator - other.numerator, self.denominator, self.meta, ) } else { FractionBase::new( - self.numerator * &other.denominator - &other.numerator * &self.denominator, - self.denominator * &other.denominator, + self.numerator * other.denominator - other.numerator * self.denominator, + self.denominator * other.denominator, self.meta, ) } @@ -331,8 +328,8 @@ impl Mul<&Self> for FractionLike { #[inline] fn mul(self, other: &Self) -> Self::Output { FractionBase::new( - self.numerator * &other.numerator, - self.denominator * &other.denominator, + self.numerator * other.numerator, + self.denominator * other.denominator, self.meta, ) } @@ -341,7 +338,6 @@ impl Mul<&Self> for FractionLike { impl Div for FractionLike { type Output = Self; - /// There's little to no possibility of an error, so unwrap can be used #[inline] fn div(self, other: Self) -> Self::Output { FractionBase::new( @@ -355,12 +351,11 @@ impl Div for FractionLike { impl Div<&Self> for FractionLike { type Output = Self; - /// There's little to no possibility of an error, so unwrap can be used #[inline] fn div(self, other: &Self) -> Self::Output { FractionBase::new( - self.numerator * &other.denominator, - self.denominator * &other.numerator, + self.numerator * other.denominator, + self.denominator * other.numerator, self.meta, ) } diff --git a/src/entities/fractions/price.rs b/src/entities/fractions/price.rs index 5bafc4d..125c2f8 100644 --- a/src/entities/fractions/price.rs +++ b/src/entities/fractions/price.rs @@ -1,4 +1,5 @@ use crate::prelude::*; +use fastnum::i512; /// Type alias for a Price, a [`FractionLike`] with metadata [`PriceMeta`] pub type Price = FractionLike>; @@ -35,8 +36,8 @@ where ) -> Self { // Calculate scalar based on decimal places of base and quote currencies let scalar = Fraction::new( - BigInt::from(10).pow(base_currency.decimals() as u32), - BigInt::from(10).pow(quote_currency.decimals() as u32), + i512!(10).pow(base_currency.decimals() as u32), + i512!(10).pow(quote_currency.decimals() as u32), ); FractionBase::new( numerator, @@ -70,8 +71,8 @@ where Price::new( self.quote_currency.clone(), self.base_currency.clone(), - self.numerator.clone(), - self.denominator.clone(), + self.numerator, + self.denominator, ) } diff --git a/src/entities/token.rs b/src/entities/token.rs index 79cdde6..f47f54c 100644 --- a/src/entities/token.rs +++ b/src/entities/token.rs @@ -4,14 +4,14 @@ use crate::prelude::*; pub type Token = CurrencyLike; /// Represents the metadata for an ERC20 token, including its address and optional fees. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] pub struct TokenMeta { /// The address of the token. pub address: Address, /// The buy fee in basis points (bps) for the token. - pub buy_fee_bps: Option, + pub buy_fee_bps: u64, /// The sell fee in basis points (bps) for the token. - pub sell_fee_bps: Option, + pub sell_fee_bps: u64, } macro_rules! impl_base_currency { @@ -62,8 +62,8 @@ impl Token { decimals: u8, symbol: Option, name: Option, - buy_fee_bps: Option, - sell_fee_bps: Option, + buy_fee_bps: u64, + sell_fee_bps: u64, ) -> Self { assert!(chain_id != 0, "chain id can't be zero"); Self { @@ -135,8 +135,8 @@ macro_rules! token { $decimals, None, None, - None, - None, + 0, + 0, ) }; ($chain_id:expr, $address:expr, $decimals:expr) => { @@ -146,8 +146,8 @@ macro_rules! token { $decimals, None, None, - None, - None, + 0, + 0, ) }; ($chain_id:expr, $address:literal, $decimals:expr, $symbol:expr) => { @@ -157,8 +157,8 @@ macro_rules! token { $decimals, Some($symbol.to_string()), None, - None, - None, + 0, + 0, ) }; ($chain_id:expr, $address:expr, $decimals:expr, $symbol:expr) => { @@ -168,8 +168,8 @@ macro_rules! token { $decimals, Some($symbol.to_string()), None, - None, - None, + 0, + 0, ) }; ($chain_id:expr, $address:literal, $decimals:expr, $symbol:expr, $name:expr) => { @@ -179,8 +179,8 @@ macro_rules! token { $decimals, Some($symbol.to_string()), Some($name.to_string()), - None, - None, + 0, + 0, ) }; ($chain_id:expr, $address:expr, $decimals:expr, $symbol:expr, $name:expr) => { @@ -190,8 +190,8 @@ macro_rules! token { $decimals, Some($symbol.to_string()), Some($name.to_string()), - None, - None, + 0, + 0, ) }; } diff --git a/src/examples/token_example.rs b/src/examples/token_example.rs index c76ecba..501b57a 100644 --- a/src/examples/token_example.rs +++ b/src/examples/token_example.rs @@ -12,8 +12,8 @@ fn main() { 18, // Decimals for DAI Some("DAI".to_string()), // Symbol for DAI Some("Dai Stablecoin".to_string()), // Name for DAI - None, // Assuming no buy fee - None, // Assuming no sell fee + 0, // Assuming no buy fee + 0, // Assuming no sell fee ); // Print the token's address and decimals diff --git a/src/lib.rs b/src/lib.rs index a0e7245..6d1b2e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,10 +49,10 @@ pub mod prelude { pub use alloc::{string::String, vec::Vec}; pub use alloy_primitives::{map::rustc_hash::FxHashMap, Address, Bytes, B256, U256}; - pub type BigInt = num_bigint::BigInt; - pub type BigUint = num_bigint::BigUint; - pub type BigDecimal = bigdecimal::BigDecimal; - pub type RoundingMode = bigdecimal::RoundingMode; + pub type BigInt = fastnum::I512; + pub type BigUint = fastnum::U512; + pub type BigDecimal = fastnum::UD512; + pub type RoundingMode = fastnum::decimal::RoundingMode; } /// Contains examples of how Uniswap sdk core can be used diff --git a/src/utils/compute_zksync_create2_address.rs b/src/utils/compute_zksync_create2_address.rs index f34ad6d..689e87f 100644 --- a/src/utils/compute_zksync_create2_address.rs +++ b/src/utils/compute_zksync_create2_address.rs @@ -32,7 +32,7 @@ mod tests { bytes[12..32].copy_from_slice(USDCE.as_slice()); bytes[44..64].copy_from_slice(WETH.as_slice()); bytes[92..96].copy_from_slice(3000_u32.to_be_bytes().as_slice()); - let salt = keccak256(&bytes); + let salt = keccak256(bytes); let result = compute_zksync_create2_address( address!("8FdA5a7a8dCA67BBcDd10F02Fa0649A937215422"), b256!("010013f177ea1fcbc4520f9a3ca7cd2d1d77959e05aa66484027cb38e712aeed"), diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 1e01754..b127140 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -2,11 +2,13 @@ pub mod compute_price_impact; pub mod compute_zksync_create2_address; pub mod sorted_insert; pub mod sqrt; +mod types; pub use compute_price_impact::compute_price_impact; pub use compute_zksync_create2_address::compute_zksync_create2_address; pub use sorted_insert::sorted_insert; pub use sqrt::sqrt; +pub use types::*; #[cfg(feature = "validate_parse_address")] pub mod validate_and_parse_address; diff --git a/src/utils/sqrt.rs b/src/utils/sqrt.rs index 1426570..f59b71d 100644 --- a/src/utils/sqrt.rs +++ b/src/utils/sqrt.rs @@ -1,4 +1,5 @@ use crate::prelude::*; +use fastnum::i512; /// Computes floor(sqrt(value)) /// @@ -8,25 +9,34 @@ use crate::prelude::*; /// /// returns: BigInt #[inline] -pub fn sqrt(value: &BigInt) -> Result { - if value < &BigInt::ZERO { - Err(Error::Invalid("NEGATIVE")) - } else { - Ok(value.sqrt()) +pub fn sqrt(value: BigInt) -> Result { + const ONE: BigInt = i512!(1); + const TWO: BigInt = i512!(2); + match value { + v if v < BigInt::ZERO => Err(Error::Invalid("NEGATIVE")), + BigInt::ZERO => Ok(BigInt::ZERO), + v if v <= TWO => Ok(ONE), + _ => { + let mut z = value; + let mut x = (value / TWO) + ONE; + while x < z { + z = x; + x = (value / x + x) / TWO; + } + Ok(z) + } } } #[cfg(test)] mod tests { use super::*; - use core::str::FromStr; #[test] fn test_sqrt_0_1000() { for i in 0..1000 { - let sqrt_i = sqrt(&BigInt::from(i)); assert_eq!( - sqrt_i.unwrap(), + sqrt(BigInt::from(i)).unwrap(), BigInt::from((i as f64).sqrt().floor() as i64) ); } @@ -36,14 +46,14 @@ mod tests { fn test_sqrt_2_powers() { for i in 0..256 { let root = BigInt::from(2).pow(i as u32); - let root_squared = &root * &root; - assert_eq!(sqrt(&root_squared).unwrap(), root); + let root_squared = root * root; + assert_eq!(sqrt(root_squared).unwrap(), root); } } #[test] fn test_sqrt_max_uint256() { - let expected_sqrt = BigInt::from_str("340282366920938463463374607431768211455").unwrap(); - assert_eq!(sqrt(&MAX_UINT256.clone()).unwrap(), expected_sqrt); + let expected_sqrt = i512!(340282366920938463463374607431768211455); + assert_eq!(sqrt(MAX_UINT256).unwrap(), expected_sqrt); } } diff --git a/src/utils/types.rs b/src/utils/types.rs new file mode 100644 index 0000000..51e2931 --- /dev/null +++ b/src/utils/types.rs @@ -0,0 +1,21 @@ +use crate::prelude::{BigDecimal, BigInt, BigUint}; +use alloy_primitives::U256; +use fastnum::decimal::Context; + +#[inline] +#[must_use] +pub const fn to_big_decimal(value: BigInt) -> BigDecimal { + BigDecimal::from_parts(value.to_bits(), 0, Context::default()) +} + +#[inline] +#[must_use] +pub const fn to_big_uint(x: U256) -> BigUint { + BigUint::from_le_slice(x.as_le_slice()).unwrap() +} + +#[inline] +#[must_use] +pub const fn to_big_int(x: U256) -> BigInt { + BigInt::from_bits(to_big_uint(x)) +} From bba761d5be1c30bce4e2377cad46e130390cbb88 Mon Sep 17 00:00:00 2001 From: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com> Date: Sun, 5 Jan 2025 04:09:25 -0500 Subject: [PATCH 2/2] Refactor `BigDecimal` handling and fix `to_big_decimal`. Updated the `BigDecimal` type alias to `fastnum::D512` for consistency. Modified the `to_big_decimal` function to account for the sign of the input, ensuring proper construction of `BigDecimal` instances. --- src/lib.rs | 2 +- src/utils/types.rs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6d1b2e2..f10d370 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,7 +51,7 @@ pub mod prelude { pub type BigInt = fastnum::I512; pub type BigUint = fastnum::U512; - pub type BigDecimal = fastnum::UD512; + pub type BigDecimal = fastnum::D512; pub type RoundingMode = fastnum::decimal::RoundingMode; } diff --git a/src/utils/types.rs b/src/utils/types.rs index 51e2931..e9e921e 100644 --- a/src/utils/types.rs +++ b/src/utils/types.rs @@ -1,11 +1,14 @@ use crate::prelude::{BigDecimal, BigInt, BigUint}; use alloy_primitives::U256; -use fastnum::decimal::Context; +use fastnum::decimal::{Context, Sign}; #[inline] #[must_use] pub const fn to_big_decimal(value: BigInt) -> BigDecimal { - BigDecimal::from_parts(value.to_bits(), 0, Context::default()) + match value.is_negative() { + false => BigDecimal::from_parts(value.to_bits(), 0, Sign::Plus, Context::default()), + true => BigDecimal::from_parts(value.to_bits(), 0, Sign::Minus, Context::default()), + } } #[inline]