From 5730e4c18e7c93dc99b92d9212aece8a55d0d3bd Mon Sep 17 00:00:00 2001 From: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com> Date: Sun, 3 Mar 2024 21:27:56 -0500 Subject: [PATCH] chore(doc): Update code formatting and documentation (#41) * chore(doc): Update code formatting and documentation Reformatted code to adhere to a maximum line width of 100 characters and better comment wrapping. Updated package version and certain dependency versions. Updated access modifiers for utility functions and entity functions to public. Improved code readability and maintainability without changing functionality. * Update GitHub Actions cache key in Rust workflow The cache key in the Rust GitHub Actions workflow has been updated. Previously, it was based on hashing the Cargo.lock file, but now this key is based on hashing the Cargo.toml file, as it offers more consistency. --- .github/workflows/rust.yml | 4 +- Cargo.toml | 4 +- rustfmt.toml | 2 + src/entities/mod.rs | 14 +++---- src/entities/pool.rs | 31 +++++++++----- src/entities/position.rs | 42 +++++++++++-------- src/entities/tick_data_provider.rs | 4 +- src/entities/trade.rs | 52 +++++++++++++++--------- src/extensions/mod.rs | 8 ---- src/extensions/position.rs | 16 +++++--- src/extensions/price_tick_conversions.rs | 52 ++++++++++++++---------- src/lib.rs | 19 +++++---- src/nonfungible_position_manager.rs | 9 ++-- src/self_permit.rs | 4 +- src/staker.rs | 14 ++++--- src/swap_router.rs | 3 +- src/tests.rs | 12 +++--- src/utils/compute_pool_address.rs | 3 +- src/utils/full_math.rs | 6 ++- src/utils/max_liquidity_for_amounts.rs | 17 ++++---- src/utils/mod.rs | 30 +++++++------- src/utils/price_tick_conversions.rs | 9 ++-- src/utils/sqrt_price_math.rs | 21 ++++++---- src/utils/swap_math.rs | 15 ++++--- src/utils/tick_math.rs | 19 +++++---- src/utils/types.rs | 5 +++ 26 files changed, 241 insertions(+), 174 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 4fe0deb..56063b6 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -25,7 +25,7 @@ jobs: ~/.cargo/registry ~/.cargo/git target - key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.toml') }} restore-keys: | ${{ runner.os }}-cargo-registry- - name: Install Rust toolchain via rustup @@ -55,7 +55,7 @@ jobs: ~/.cargo/registry ~/.cargo/git target - key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.toml') }} restore-keys: | ${{ runner.os }}-cargo-registry- - name: Build diff --git a/Cargo.toml b/Cargo.toml index 4c4926e..de29192 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "uniswap-v3-sdk" -version = "0.25.0" +version = "0.26.0" edition = "2021" authors = ["Shuhui Luo "] description = "Uniswap V3 SDK for Rust" @@ -30,7 +30,7 @@ regex = { version = "1.10", optional = true } ruint = "1.12" serde_json = { version = "1.0", optional = true } thiserror = "1.0" -uniswap-sdk-core = "0.16" +uniswap-sdk-core = "0.18" uniswap_v3_math = "0.4" [features] diff --git a/rustfmt.toml b/rustfmt.toml index 4daad80..c4aa2b3 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -3,3 +3,5 @@ imports_granularity = "Crate" max_width = 100 unstable_features = true use_field_init_shorthand = true +wrap_comments = true +comment_width = 100 diff --git a/src/entities/mod.rs b/src/entities/mod.rs index 0a87f62..f7a680e 100644 --- a/src/entities/mod.rs +++ b/src/entities/mod.rs @@ -1,10 +1,10 @@ -mod pool; -mod position; -mod route; -mod tick; -mod tick_data_provider; -mod tick_list_data_provider; -mod trade; +pub mod pool; +pub mod position; +pub mod route; +pub mod tick; +pub mod tick_data_provider; +pub mod tick_list_data_provider; +pub mod trade; pub use pool::{get_address, Pool}; pub use position::{MintAmounts, Position}; diff --git a/src/entities/pool.rs b/src/entities/pool.rs index 44350d7..8169e2b 100644 --- a/src/entities/pool.rs +++ b/src/entities/pool.rs @@ -68,7 +68,8 @@ impl Pool { /// /// * `token_a`: One of the tokens in the pool /// * `token_b`: The other token in the pool - /// * `fee`: The fee in hundredths of a bips of the input amount of every swap that is collected by the pool + /// * `fee`: The fee in hundredths of a bips of the input amount of every swap that is collected + /// by the pool /// * `sqrt_ratio_x96`: The sqrt of the current ratio of amounts of token1 to token0 /// * `liquidity`: The current value of in range liquidity /// * `tick_current`: The current tick of the pool @@ -142,7 +143,8 @@ impl

Pool

{ self.token0.equals(token) || self.token1.equals(token) } - /// Returns the current mid price of the pool in terms of token0, i.e. the ratio of token1 over token0 + /// Returns the current mid price of the pool in terms of token0, i.e. the ratio of token1 over + /// token0 pub fn token0_price(&self) -> Price { let sqrt_ratio_x96: BigUint = u256_to_big_uint(self.sqrt_ratio_x96); Price::new( @@ -153,7 +155,8 @@ impl

Pool

{ ) } - /// Returns the current mid price of the pool in terms of token1, i.e. the ratio of token0 over token1 + /// Returns the current mid price of the pool in terms of token1, i.e. the ratio of token0 over + /// token1 pub fn token1_price(&self) -> Price { let sqrt_ratio_x96: BigUint = u256_to_big_uint(self.sqrt_ratio_x96); Price::new( @@ -192,7 +195,8 @@ where /// /// * `token_a`: One of the tokens in the pool /// * `token_b`: The other token in the pool - /// * `fee`: The fee in hundredths of a bips of the input amount of every swap that is collected by the pool + /// * `fee`: The fee in hundredths of a bips of the input amount of every swap that is collected + /// by the pool /// * `sqrt_ratio_x96`: The sqrt of the current ratio of amounts of token1 to token0 /// * `liquidity`: The current value of in range liquidity /// * `tick_current`: The current tick of the pool @@ -221,7 +225,8 @@ where }) } - /// Given an input amount of a token, return the computed output amount, and a pool with state updated after the trade + /// Given an input amount of a token, return the computed output amount, and a pool with state + /// updated after the trade /// /// ## Arguments /// @@ -261,13 +266,15 @@ where )) } - /// Given a desired output amount of a token, return the computed input amount and a pool with state updated after the trade + /// Given a desired output amount of a token, return the computed input amount and a pool with + /// state updated after the trade /// /// ## Arguments /// /// * `output_amount`: the output amount for which to quote the input amount - /// * `sqrt_price_limit_x96`: The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this value - /// after the swap. If one for zero, the price cannot be greater than this value after the swap + /// * `sqrt_price_limit_x96`: The Q64.96 sqrt price limit. If zero for one, the price cannot be + /// less than this value after the swap. If one for zero, the price cannot be greater than + /// this value after the swap /// /// returns: The input amount and the pool with updated state pub fn get_input_amount( @@ -350,8 +357,9 @@ where }; step.sqrt_price_start_x96 = state.sqrt_price_x96; - // because each iteration of the while loop rounds, we can't optimize this code (relative to the smart contract) - // by simply traversing to the next available tick, we instead need to exactly replicate + // because each iteration of the while loop rounds, we can't optimize this code + // (relative to the smart contract) by simply traversing to the next available tick, we + // instead need to exactly replicate (step.tick_next, step.initialized) = self .tick_data_provider .next_initialized_tick_within_one_word( @@ -414,7 +422,8 @@ where } state.tick = step.tick_next - zero_for_one as i32; } else { - // recompute unless we're on a lower tick boundary (i.e. already transitioned ticks), and haven't moved + // recompute unless we're on a lower tick boundary (i.e. already transitioned + // ticks), and haven't moved state.tick = get_tick_at_sqrt_ratio(state.sqrt_price_x96)?; } } diff --git a/src/entities/position.rs b/src/entities/position.rs index f84c9ad..0dab8f1 100644 --- a/src/entities/position.rs +++ b/src/entities/position.rs @@ -90,7 +90,8 @@ impl

Position

{ ) } - /// Returns the amount of token0 that this position's liquidity could be burned for at the current pool price + /// Returns the amount of token0 that this position's liquidity could be burned for at the + /// current pool price pub fn amount0(&mut self) -> Result> { if self._token0_amount.is_none() { if self.pool.tick_current < self.tick_lower { @@ -123,7 +124,8 @@ impl

Position

{ Ok(self._token0_amount.clone().unwrap()) } - /// Returns the amount of token1 that this position's liquidity could be burned for at the current pool price + /// Returns the amount of token1 that this position's liquidity could be burned for at the + /// current pool price pub fn amount1(&mut self) -> Result> { if self._token1_amount.is_none() { if self.pool.tick_current < self.tick_lower { @@ -156,11 +158,13 @@ impl

Position

{ Ok(self._token1_amount.clone().unwrap()) } - /// Returns the lower and upper sqrt ratios if the price 'slips' up to slippage tolerance percentage + /// Returns the lower and upper sqrt ratios if the price 'slips' up to slippage tolerance + /// percentage /// /// ## Arguments /// - /// * `slippage_tolerance`: The amount by which the price can 'slip' before the transaction will revert + /// * `slippage_tolerance`: The amount by which the price can 'slip' before the transaction will + /// revert /// /// ## Returns /// @@ -187,7 +191,8 @@ impl

Position

{ (sqrt_ratio_x96_lower, sqrt_ratio_x96_upper) } - /// Returns the minimum amounts that must be sent in order to safely mint the amount of liquidity held by the position + /// Returns the minimum amounts that must be sent in order to safely mint the amount of + /// liquidity held by the position /// /// ## Arguments /// @@ -220,7 +225,8 @@ impl

Position

{ 0, // liquidity doesn't matter )?; - // Because the router is imprecise, we need to calculate the position that will be created (assuming no slippage) + // Because the router is imprecise, we need to calculate the position that will be created + // (assuming no slippage) let MintAmounts { amount0, amount1 } = self.mint_amounts()?; let position_that_will_be_created = Position::from_amounts( Pool::new( @@ -260,8 +266,8 @@ impl

Position

{ Ok(MintAmounts { amount0, amount1 }) } - /// Returns the minimum amounts that should be requested in order to safely burn the amount of liquidity held by the - /// position with the given slippage tolerance + /// Returns the minimum amounts that should be requested in order to safely burn the amount of + /// liquidity held by the position with the given slippage tolerance /// /// ## Arguments /// @@ -304,8 +310,8 @@ impl

Position

{ Ok((big_int_to_u256(amount0), big_int_to_u256(amount1))) } - /// Returns the minimum amounts that must be sent in order to mint the amount of liquidity held by the position at - /// the current price for the pool + /// Returns the minimum amounts that must be sent in order to mint the amount of liquidity held + /// by the position at the current price for the pool pub fn mint_amounts(&mut self) -> Result { if self._mint_amounts.is_none() { if self.pool.tick_current < self.tick_lower { @@ -358,8 +364,8 @@ impl

Position

{ /// * `tick_upper`: The upper tick of the position /// * `amount0`: token0 amount /// * `amount1`: token1 amount - /// * `use_full_precision`: If false, liquidity will be maximized according to what the router can calculate, - /// not what core can theoretically support + /// * `use_full_precision`: If false, liquidity will be maximized according to what the router + /// can calculate, not what core can theoretically support /// /// ## Returns /// @@ -390,8 +396,8 @@ impl

Position

{ )) } - /// Computes a position with the maximum amount of liquidity received for a given amount of token0, - /// assuming an unlimited amount of token1 + /// Computes a position with the maximum amount of liquidity received for a given amount of + /// token0, assuming an unlimited amount of token1 /// /// ## Arguments /// @@ -399,8 +405,8 @@ impl

Position

{ /// * `tick_lower`: The lower tick /// * `tick_upper`: The upper tick /// * `amount0`: The desired amount of token0 - /// * `use_full_precision`: If true, liquidity will be maximized according to what the router can calculate, - /// not what core can theoretically support + /// * `use_full_precision`: If true, liquidity will be maximized according to what the router + /// can calculate, not what core can theoretically support pub fn from_amount0( pool: Pool

, tick_lower: i32, @@ -418,8 +424,8 @@ impl

Position

{ ) } - /// Computes a position with the maximum amount of liquidity received for a given amount of token1, - /// assuming an unlimited amount of token0 + /// Computes a position with the maximum amount of liquidity received for a given amount of + /// token1, assuming an unlimited amount of token0 /// /// ## Arguments /// diff --git a/src/entities/tick_data_provider.rs b/src/entities/tick_data_provider.rs index ac2babb..8bb1c38 100644 --- a/src/entities/tick_data_provider.rs +++ b/src/entities/tick_data_provider.rs @@ -36,8 +36,8 @@ pub trait TickDataProvider: Clone { #[error("No tick data provider was given")] pub struct NoTickDataError; -/// This tick data provider does not know how to fetch any tick data. It throws whenever it is required. -/// Useful if you do not need to load tick data for your use case. +/// This tick data provider does not know how to fetch any tick data. It throws whenever it is +/// required. Useful if you do not need to load tick data for your use case. #[derive(Clone, Debug)] pub struct NoTickDataProvider; diff --git a/src/entities/trade.rs b/src/entities/trade.rs index a6e37a0..8425642 100644 --- a/src/entities/trade.rs +++ b/src/entities/trade.rs @@ -3,7 +3,8 @@ use anyhow::Result; use std::{cell::RefCell, collections::HashSet}; use uniswap_sdk_core::prelude::{sorted_insert::sorted_insert, *}; -/// Trades comparator, an extension of the input output comparator that also considers other dimensions of the trade in ranking them +/// Trades comparator, an extension of the input output comparator that also considers other +/// dimensions of the trade in ranking them /// /// ## Arguments /// @@ -79,15 +80,17 @@ pub struct Swap { pub output_amount: CurrencyAmount, } -/// Represents a trade executed against a set of routes where some percentage of the input is split across each route. +/// Represents a trade executed against a set of routes where some percentage of the input is split +/// across each route. /// /// Each route has its own set of pools. Pools can not be re-used across routes. /// -/// Does not account for slippage, i.e., changes in price environment that can occur between the time the trade is -/// submitted and when it is executed. +/// Does not account for slippage, i.e., changes in price environment that can occur between the +/// time the trade is submitted and when it is executed. #[derive(Clone, PartialEq, Debug)] pub struct Trade { - /// The swaps of the trade, i.e. which routes and how much is swapped in each that make up the trade. + /// The swaps of the trade, i.e. which routes and how much is swapped in each that make up the + /// trade. pub swaps: Vec>, /// The type of the trade, either exact in or exact out. pub trade_type: TradeType, @@ -251,7 +254,8 @@ where /// /// ## Arguments /// - /// * `routes`: The routes to swap through and how much of the amount should be routed through each + /// * `routes`: The routes to swap through and how much of the amount should be routed through + /// each /// * `trade_type`: Whether the trade is an exact input or exact output swap pub fn from_routes( routes: Vec<( @@ -295,18 +299,20 @@ where Self::new(swaps, trade_type) } - /// Given a list of pools, and a fixed amount in, returns the top `max_num_results` trades that go from an input token - /// amount to an output token, making at most `max_hops` hops. + /// Given a list of pools, and a fixed amount in, returns the top `max_num_results` trades that + /// go from an input token amount to an output token, making at most `max_hops` hops. /// /// ## Arguments /// /// * `pools`: The pools to consider in finding the best trade /// * `currency_amount_in`: The exact amount of input currency to spend /// * `currency_out`: The desired currency out - /// * `best_trade_options`: Maximum number of results to return and maximum number of hops a returned trade can make, + /// * `best_trade_options`: Maximum number of results to return and maximum number of hops a + /// returned trade can make, /// e.g. 1 hop goes through a single pool /// * `current_pools`: Used in recursion; the current list of pools - /// * `next_amount_in`: Used in recursion; the original value of the currency_amount_in parameter + /// * `next_amount_in`: Used in recursion; the original value of the currency_amount_in + /// parameter /// * `best_trades`: Used in recursion; the current list of best trades pub fn best_trade_exact_in( pools: Vec>, @@ -361,7 +367,8 @@ where .filter(|p| p.address(None, None) != pool.address(None, None)) .cloned() .collect(); - // otherwise, consider all the other paths that lead from this token as long as we have not exceeded maxHops + // otherwise, consider all the other paths that lead from this token as long as we + // have not exceeded maxHops let mut next_pools = current_pools.clone(); next_pools.push(pool.clone()); Self::best_trade_exact_in( @@ -381,18 +388,19 @@ where Ok(best_trades) } - /// Given a list of pools, and a fixed amount out, returns the top `max_num_results` trades that go from an input token - /// to an output token amount, making at most `max_hops` hops. + /// Given a list of pools, and a fixed amount out, returns the top `max_num_results` trades that + /// go from an input token to an output token amount, making at most `max_hops` hops. /// - /// Note this does not consider aggregation, as routes are linear. It's possible a better route exists by splitting - /// the amount in among multiple routes. + /// Note this does not consider aggregation, as routes are linear. It's possible a better route + /// exists by splitting the amount in among multiple routes. /// /// ## Arguments /// /// * `pools`: The pools to consider in finding the best trade /// * `currency_in`: The currency to spend /// * `currency_amount_out`: The desired currency amount out - /// * `best_trade_options`: Maximum number of results to return and maximum number of hops a returned trade can make, + /// * `best_trade_options`: Maximum number of results to return and maximum number of hops a + /// returned trade can make, /// e.g. 1 hop goes through a single pool /// * `current_pools`: Used in recursion; the current list of pools /// * `next_amount_out`: Used in recursion; the exact amount of currency out @@ -451,7 +459,8 @@ where .filter(|p| p.address(None, None) != pool.address(None, None)) .cloned() .collect(); - // otherwise, consider all the other paths that arrive at this token as long as we have not exceeded maxHops + // otherwise, consider all the other paths that arrive at this token as long as we + // have not exceeded maxHops let mut next_pools = vec![pool.clone()]; next_pools.extend(current_pools.clone()); Self::best_trade_exact_out( @@ -565,11 +574,13 @@ where Ok(self._price_impact.clone().unwrap()) } - /// Get the minimum amount that must be received from this trade for the given slippage tolerance + /// Get the minimum amount that must be received from this trade for the given slippage + /// tolerance /// /// ## Arguments /// - /// * `slippage_tolerance`: The tolerance of unfavorable slippage from the execution price of this trade + /// * `slippage_tolerance`: The tolerance of unfavorable slippage from the execution price of + /// this trade /// * `amount_out`: The amount to receive pub fn minimum_amount_out( &mut self, @@ -598,7 +609,8 @@ where /// /// ## Arguments /// - /// * `slippage_tolerance`: The tolerance of unfavorable slippage from the execution price of this trade + /// * `slippage_tolerance`: The tolerance of unfavorable slippage from the execution price of + /// this trade /// * `amount_in`: The amount to spend pub fn maximum_amount_in( &mut self, diff --git a/src/extensions/mod.rs b/src/extensions/mod.rs index 087299c..6f72899 100644 --- a/src/extensions/mod.rs +++ b/src/extensions/mod.rs @@ -9,11 +9,3 @@ pub use ephemeral_tick_data_provider::EphemeralTickDataProvider; pub use pool::*; pub use position::*; pub use price_tick_conversions::*; - -use crate::prelude::*; -use alloy_primitives::U256; -use bigdecimal::BigDecimal; - -pub fn u256_to_big_decimal(x: U256) -> BigDecimal { - BigDecimal::from(u256_to_big_int(x)) -} diff --git a/src/extensions/position.rs b/src/extensions/position.rs index b3d16e9..c4bcf51 100644 --- a/src/extensions/position.rs +++ b/src/extensions/position.rs @@ -1,6 +1,7 @@ //! ## Position Extension //! This module provides functions to create a [`Position`] struct from the token id, get the state -//! and pool for all positions of the specified owner by deploying an ephemeral contract via `eth_call`, etc. +//! and pool for all positions of the specified owner by deploying an ephemeral contract via +//! `eth_call`, etc. use crate::prelude::*; use alloy_primitives::{Address, ChainId, U256}; @@ -72,7 +73,8 @@ pub async fn get_position( } impl Position { - /// Get a [`Position`] struct from the token id in a single call by deploying an ephemeral contract via `eth_call` + /// Get a [`Position`] struct from the token id in a single call by deploying an ephemeral + /// contract via `eth_call` /// /// ## Arguments /// @@ -121,12 +123,13 @@ impl Position { } } -/// Get the state and pool for all positions of the specified owner by deploying an ephemeral contract via `eth_call`. +/// Get the state and pool for all positions of the specified owner by deploying an ephemeral +/// contract via `eth_call`. /// /// ## Note /// -/// Each position consumes about 200k gas, so this method may fail if the number of positions exceeds 1500 assuming the -/// provider gas limit is 300m. +/// Each position consumes about 200k gas, so this method may fail if the number of positions +/// exceeds 1500 assuming the provider gas limit is 300m. /// /// ## Arguments /// @@ -572,7 +575,8 @@ mod tests { .unwrap() .quotient() .is_zero()); - // if rebalancing at the upper tick, `token0` are bought back at a higher price, hence `amount0` will be lower + // if rebalancing at the upper tick, `token0` are bought back at a higher price, hence + // `amount0` will be lower assert!((position_rebalanced_at_current_price.amount0().unwrap() - position_rebalanced_at_tick_upper.amount0().unwrap()) .quotient() diff --git a/src/extensions/price_tick_conversions.rs b/src/extensions/price_tick_conversions.rs index 1400b2f..5404d4f 100644 --- a/src/extensions/price_tick_conversions.rs +++ b/src/extensions/price_tick_conversions.rs @@ -1,6 +1,6 @@ //! ## Price and tick conversions -//! Utility functions for converting between [`i32`] ticks, [`BigDecimal`] prices, and SDK Core [`Price`] prices. -//! Ported from [uniswap-v3-automation-sdk](https://github.com/Aperture-Finance/uniswap-v3-automation-sdk/blob/8bc54456753f454848d25029631f4e64ff573e12/price.ts). +//! Utility functions for converting between [`i32`] ticks, [`BigDecimal`] prices, and SDK Core +//! [`Price`] prices. Ported from [uniswap-v3-automation-sdk](https://github.com/Aperture-Finance/uniswap-v3-automation-sdk/blob/8bc54456753f454848d25029631f4e64ff573e12/price.ts). use crate::prelude::*; use alloy_primitives::U256; @@ -37,12 +37,12 @@ pub static MAX_PRICE: Lazy = Lazy::new(|| { /// ## Examples /// /// ``` -/// use uniswap_sdk_core::{prelude::Token, token}; +/// use uniswap_sdk_core::{prelude::*, token}; /// use uniswap_v3_sdk::prelude::parse_price; /// /// let price = parse_price( -/// token!(1, "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", 8, "WBTC"), -/// token!(1, "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", 18, "WETH"), +/// token!(1, "2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", 8, "WBTC"), +/// token!(1, "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", 18, "WETH"), /// "10.23", /// ) /// .unwrap(); @@ -57,7 +57,8 @@ where TQuote: CurrencyTrait, { // Check whether `price` is a valid string of decimal number. - // This regex matches any number of digits optionally followed by '.' which is then followed by at least one digit. + // This regex matches any number of digits optionally followed by '.' which is then followed by + // at least one digit. let re = Regex::new(r"^\d*\.?\d+$").unwrap(); if !re.is_match(price) { bail!("Invalid price string"); @@ -78,22 +79,24 @@ where /// /// ## Arguments /// -/// * `sqrt_ratio_x96`: The sqrt ratio of the base token in terms of the quote token as a Q64.96 [`U256`]. +/// * `sqrt_ratio_x96`: The sqrt ratio of the base token in terms of the quote token as a Q64.96 +/// [`U256`]. /// * `base_token`: The base token. /// * `quote_token`: The quote token. /// /// ## Returns /// -/// The price of the base token in terms of the quote token as an instance of [`Price`] in [`uniswap_sdk_core`]. +/// The price of the base token in terms of the quote token as an instance of [`Price`] in +/// [`uniswap_sdk_core`]. /// /// ## Examples /// /// ``` -/// use uniswap_sdk_core::{prelude::Token, token}; +/// use uniswap_sdk_core::{prelude::*, token}; /// use uniswap_v3_sdk::prelude::*; /// -/// let token0 = token!(1, "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", 8, "WBTC"); -/// let token1 = token!(1, "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", 18, "WETH"); +/// let token0 = token!(1, "2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", 8, "WBTC"); +/// let token1 = token!(1, "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", 18, "WETH"); /// let min_price = tick_to_price(token0.clone(), token1.clone(), MIN_TICK).unwrap(); /// assert_eq!( /// sqrt_ratio_x96_to_price(MIN_SQRT_RATIO, token0, token1).unwrap(), @@ -114,7 +117,8 @@ pub fn sqrt_ratio_x96_to_price( }) } -/// Same as [`price_to_closest_tick`] but returns [`MIN_TICK`] or [`MAX_TICK`] if the price is outside Uniswap's range. +/// Same as [`price_to_closest_tick`] but returns [`MIN_TICK`] or [`MAX_TICK`] if the price is +/// outside Uniswap's range. pub fn price_to_closest_tick_safe(price: &Price) -> Result { let sorted = price.base_currency.sorts_before(&price.quote_currency)?; if price.as_fraction() < *MIN_PRICE { @@ -130,7 +134,8 @@ pub fn price_to_closest_tick_safe(price: &Price) -> Result { /// /// ## Arguments /// -/// * `price`: The price of two tokens in the liquidity pool. Either token0 or token1 may be the base token. +/// * `price`: The price of two tokens in the liquidity pool. Either token0 or token1 may be the +/// base token. /// * `fee`: The liquidity pool fee tier. /// /// ## Returns @@ -143,8 +148,8 @@ pub fn price_to_closest_tick_safe(price: &Price) -> Result { /// use uniswap_sdk_core::{prelude::*, token}; /// use uniswap_v3_sdk::prelude::*; /// -/// let token0 = token!(1, "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", 8, "WBTC"); -/// let token1 = token!(1, "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", 18, "WETH"); +/// let token0 = token!(1, "2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", 8, "WBTC"); +/// let token1 = token!(1, "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", 18, "WETH"); /// let fee = FeeAmount::MEDIUM; /// let min_price = Price::new(token0.clone(), token1.clone(), MIN_PRICE.denominator(), 1); /// let max_price = Price::new( @@ -236,18 +241,20 @@ pub fn price_to_sqrt_ratio_x96(price: &BigDecimal) -> U256 { } } -/// For a given tick range from `tick_lower` to `tick_upper`, and a given proportion of the position value that is held in -/// token0, calculate the price of token0 denominated in token1. +/// For a given tick range from `tick_lower` to `tick_upper`, and a given proportion of the position +/// value that is held in token0, calculate the price of token0 denominated in token1. /// /// ## Arguments /// -/// * `token0_ratio`: The proportion of the position value that is held in token0, as a [`BigDecimal`] between 0 and 1, inclusive. +/// * `token0_ratio`: The proportion of the position value that is held in token0, as a +/// [`BigDecimal`] between 0 and 1, inclusive. /// * `tick_lower`: The lower tick of the range. /// * `tick_upper`: The upper tick of the range. /// /// ## Returns /// -/// The price of token0 denominated in token1 for the specified tick range and token0 value proportion. +/// The price of token0 denominated in token1 for the specified tick range and token0 value +/// proportion. pub fn token0_ratio_to_price( token0_ratio: BigDecimal, tick_lower: i32, @@ -278,8 +285,8 @@ pub fn token0_ratio_to_price( Ok((numerator / denominator).square()) } -/// Given a price ratio of token1/token0, calculate the proportion of the position value that is held in token0 for a -/// given tick range. Inverse of [`token0_ratio_to_price`]. +/// Given a price ratio of token1/token0, calculate the proportion of the position value that is +/// held in token0 for a given tick range. Inverse of [`token0_ratio_to_price`]. /// /// ## Arguments /// @@ -289,7 +296,8 @@ pub fn token0_ratio_to_price( /// /// ## Returns /// -/// The proportion of the position value that is held in token0, as a [`BigDecimal`] between 0 and 1, inclusive. +/// The proportion of the position value that is held in token0, as a [`BigDecimal`] between 0 and +/// 1, inclusive. pub fn token0_price_to_ratio( price: BigDecimal, tick_lower: i32, diff --git a/src/lib.rs b/src/lib.rs index cab071e..68c5a88 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,19 +5,22 @@ //! //! ## Features //! -//! - Opinionated Rust implementation of the Uniswap V3 SDK with a focus on readability and performance +//! - Opinionated Rust implementation of the Uniswap V3 SDK with a focus on readability and +//! performance //! - Usage of [alloy-rs](https://github.com/alloy-rs) types //! - Reimplementation of the math libraries in [Uniswap V3 Math In Rust](https://github.com/0xKitsune/uniswap-v3-math) //! based on optimizations presented in [Uni V3 Lib](https://github.com/Aperture-Finance/uni-v3-lib) //! - Extensive unit tests and benchmarks -//! - An [`extensions`](./src/extensions) feature for additional functionalities related to Uniswap V3, including: +//! - An [`extensions`](./src/extensions) feature for additional functionalities related to Uniswap +//! V3, including: //! -//! - [`pool`](./src/extensions/pool.rs) module for creating a `Pool` struct from a pool key and fetching the -//! liquidity map within a tick range for the specified pool, using RPC client -//! - [`position`](./src/extensions/position.rs) module for creating a `Position` struct from a token id and fetching -//! the state and pool for all positions of the specified owner, using RPC client, etc -//! - [`price_tick_conversions`](./src/extensions/price_tick_conversions.rs) module for converting between prices and -//! ticks +//! - [`pool`](./src/extensions/pool.rs) module for creating a `Pool` struct from a pool key and +//! fetching the liquidity map within a tick range for the specified pool, using RPC client +//! - [`position`](./src/extensions/position.rs) module for creating a `Position` struct from a +//! token id and fetching the state and pool for all positions of the specified owner, using +//! RPC client, etc +//! - [`price_tick_conversions`](./src/extensions/price_tick_conversions.rs) module for +//! converting between prices and ticks //! - [`ephemeral_tick_data_provider`](./src/extensions/ephemeral_tick_data_provider.rs) module for fetching ticks using //! an [ephemeral contract](https://github.com/Aperture-Finance/Aperture-Lens/blob/904101e4daed59e02fd4b758b98b0749e70b583b/contracts/EphemeralGetPopulatedTicksInRange.sol) //! in a single `eth_call` diff --git a/src/nonfungible_position_manager.rs b/src/nonfungible_position_manager.rs index 9c7bd4f..097b2f7 100644 --- a/src/nonfungible_position_manager.rs +++ b/src/nonfungible_position_manager.rs @@ -57,9 +57,11 @@ pub struct SafeTransferOptions { pub struct CollectOptions { /// Indicates the ID of the position to collect for. pub token_id: U256, - /// Expected value of tokensOwed0, including as-of-yet-unaccounted-for fees/liquidity value to be burned + /// Expected value of tokensOwed0, including as-of-yet-unaccounted-for fees/liquidity value to + /// be burned pub expected_currency_owed0: CurrencyAmount, - /// Expected value of tokensOwed1, including as-of-yet-unaccounted-for fees/liquidity value to be burned + /// Expected value of tokensOwed1, including as-of-yet-unaccounted-for fees/liquidity value to + /// be burned pub expected_currency_owed1: CurrencyAmount, /// The account that should receive the tokens. pub recipient: Address, @@ -85,7 +87,8 @@ pub struct RemoveLiquidityOptions { pub deadline: U256, /// Whether the NFT should be burned if the entire position is being exited, by default false. pub burn_token: bool, - /// The optional permit of the token ID being exited, in case the exit transaction is being sent by an account that does not own the NFT + /// The optional permit of the token ID being exited, in case the exit transaction is being + /// sent by an account that does not own the NFT pub permit: Option, /// Parameters to be passed on to collect pub collect_options: CollectOptions, diff --git a/src/self_permit.rs b/src/self_permit.rs index fe009ee..b1eb04e 100644 --- a/src/self_permit.rs +++ b/src/self_permit.rs @@ -69,12 +69,12 @@ pub fn encode_permit(token: Token, options: PermitOptions) -> Vec { #[cfg(test)] mod tests { use super::*; - use alloy_primitives::{hex, uint}; + use alloy_primitives::{address, hex, uint}; use once_cell::sync::Lazy; use uniswap_sdk_core::token; static TOKEN: Lazy = - Lazy::new(|| token!(1, "0x0000000000000000000000000000000000000001", 18)); + Lazy::new(|| token!(1, "0000000000000000000000000000000000000001", 18)); #[test] fn test_encode_permit_standard() { diff --git a/src/staker.rs b/src/staker.rs index 67b4b75..1933a1f 100644 --- a/src/staker.rs +++ b/src/staker.rs @@ -24,7 +24,8 @@ pub struct ClaimOptions { pub struct WithdrawOptions { /// Set when withdrawing. The position will be sent to `owner` on withdraw. pub owner: Address, - /// Set when withdrawing. `data` is passed to `safeTransferFrom` when transferring the position from contract back to owner. + /// Set when withdrawing. `data` is passed to `safeTransferFrom` when transferring the position + /// from contract back to owner. pub data: Option>, } @@ -81,8 +82,9 @@ fn encode_claim

(incentive_key: &IncentiveKey

, options: ClaimOptions) -> [V /// Collect rewards from multiple programs at once. /// -/// Note: A `tokenId` can be staked in many programs but to claim rewards and continue the program you must unstake, claim, and then restake. -/// You can only specify one amount and one recipient across the various programs if you are collecting from multiple programs at once. +/// Note: A `tokenId` can be staked in many programs but to claim rewards and continue the program +/// you must unstake, claim, and then restake. You can only specify one amount and one recipient +/// across the various programs if you are collecting from multiple programs at once. /// /// ## Arguments /// @@ -116,8 +118,10 @@ pub fn collect_rewards

( /// /// ## Arguments /// -/// * `incentive_keys`: A list of incentiveKeys to unstake from. Should include all incentiveKeys (unique staking programs) that `options.tokenId` is staked in. -/// * `withdraw_options`: Options for producing claim calldata and withdraw calldata. Can't withdraw without unstaking all programs for `tokenId`. +/// * `incentive_keys`: A list of incentiveKeys to unstake from. Should include all incentiveKeys +/// (unique staking programs) that `options.tokenId` is staked in. +/// * `withdraw_options`: Options for producing claim calldata and withdraw calldata. Can't withdraw +/// without unstaking all programs for `tokenId`. pub fn withdraw_token

( incentive_keys: &[IncentiveKey

], withdraw_options: FullWithdrawOptions, diff --git a/src/swap_router.rs b/src/swap_router.rs index 75458ae..f2af589 100644 --- a/src/swap_router.rs +++ b/src/swap_router.rs @@ -21,7 +21,8 @@ pub struct SwapOptions { pub fee: Option, } -/// Produces the on-chain method name to call and the hex encoded parameters to pass as arguments for a given trade. +/// Produces the on-chain method name to call and the hex encoded parameters to pass as arguments +/// for a given trade. /// /// ## Arguments /// diff --git a/src/tests.rs b/src/tests.rs index f5bb96d..4734856 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -9,7 +9,7 @@ pub static ETHER: Lazy = Lazy::new(|| Ether::on_chain(1)); pub static TOKEN0: Lazy = Lazy::new(|| { token!( 1, - "0x0000000000000000000000000000000000000001", + "0000000000000000000000000000000000000001", 18, "t0", "token0" @@ -18,7 +18,7 @@ pub static TOKEN0: Lazy = Lazy::new(|| { pub static TOKEN1: Lazy = Lazy::new(|| { token!( 1, - "0x0000000000000000000000000000000000000002", + "0000000000000000000000000000000000000002", 18, "t1", "token1" @@ -27,7 +27,7 @@ pub static TOKEN1: Lazy = Lazy::new(|| { pub static TOKEN2: Lazy = Lazy::new(|| { token!( 1, - "0x0000000000000000000000000000000000000003", + "0000000000000000000000000000000000000003", 18, "t2", "token2" @@ -36,7 +36,7 @@ pub static TOKEN2: Lazy = Lazy::new(|| { pub static TOKEN3: Lazy = Lazy::new(|| { token!( 1, - "0x0000000000000000000000000000000000000004", + "0000000000000000000000000000000000000004", 18, "t3", "token3" @@ -46,7 +46,7 @@ pub static WETH: Lazy = Lazy::new(|| Ether::on_chain(1).wrapped()); pub static USDC: Lazy = Lazy::new(|| { token!( 1, - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", 6, "USDC", "USD Coin" @@ -55,7 +55,7 @@ pub static USDC: Lazy = Lazy::new(|| { pub static DAI: Lazy = Lazy::new(|| { token!( 1, - "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "6B175474E89094C44Da98b954EedeAC495271d0F", 18, "DAI", "DAI Stablecoin" diff --git a/src/utils/compute_pool_address.rs b/src/utils/compute_pool_address.rs index 79d3dff..6071380 100644 --- a/src/utils/compute_pool_address.rs +++ b/src/utils/compute_pool_address.rs @@ -10,7 +10,8 @@ use alloy_sol_types::SolValue; /// * `token_a`: The first token of the pair, irrespective of sort order /// * `token_b`: The second token of the pair, irrespective of sort order /// * `fee`: The fee tier of the pool -/// * `init_code_hash_manual_override`: Override the init code hash used to compute the pool address if necessary +/// * `init_code_hash_manual_override`: Override the init code hash used to compute the pool address +/// if necessary /// /// ## Returns /// diff --git a/src/utils/full_math.rs b/src/utils/full_math.rs index ad69586..3c0fc6c 100644 --- a/src/utils/full_math.rs +++ b/src/utils/full_math.rs @@ -2,7 +2,8 @@ use super::{ONE, Q96, THREE, TWO}; use alloy_primitives::U256; use uniswap_v3_math::error::UniswapV3MathError; -/// Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 +/// Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or +/// denominator == 0 /// /// ## Arguments /// @@ -94,7 +95,8 @@ pub fn mul_div(a: U256, b: U256, mut denominator: U256) -> Result = Lazy::new(|| { token!( 1, - "0x0000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000", 18, "T0", "token0" @@ -78,7 +79,7 @@ mod tests { static TOKEN1: Lazy = Lazy::new(|| { token!( 1, - "0x1111111111111111111111111111111111111111", + "1111111111111111111111111111111111111111", 18, "T1", "token1" @@ -87,7 +88,7 @@ mod tests { static TOKEN2_6DECIMALS: Lazy = Lazy::new(|| { token!( 1, - "0x2222222222222222222222222222222222222222", + "2222222222222222222222222222222222222222", 6, "T2", "token2" diff --git a/src/utils/sqrt_price_math.rs b/src/utils/sqrt_price_math.rs index 8c800ba..94dcb5f 100644 --- a/src/utils/sqrt_price_math.rs +++ b/src/utils/sqrt_price_math.rs @@ -18,11 +18,12 @@ fn to_uint160(x: U256) -> Result { /// Gets the next sqrt price given a delta of token0 /// -/// Always rounds up, because in the exact output case (increasing price) we need to move the price at least -/// far enough to get the desired output amount, and in the exact input case (decreasing price) we need to move the -/// price less in order to not send too much output. +/// Always rounds up, because in the exact output case (increasing price) we need to move the price +/// at least far enough to get the desired output amount, and in the exact input case (decreasing +/// price) we need to move the price less in order to not send too much output. /// The most precise formula for this is liquidity * sqrtPX96 / (liquidity +- amount * sqrtPX96), -/// if this is impossible because of overflow, we calculate liquidity / (liquidity / sqrtPX96 +- amount). +/// if this is impossible because of overflow, we calculate liquidity / (liquidity / sqrtPX96 +- +/// amount). /// /// ## Arguments /// @@ -72,9 +73,9 @@ pub fn get_next_sqrt_price_from_amount_0_rounding_up( /// Gets the next sqrt price given a delta of token1 /// -/// Always rounds down, because in the exact output case (decreasing price) we need to move the price at least -/// far enough to get the desired output amount, and in the exact input case (increasing price) we need to move the -/// price less in order to not send too much output. +/// Always rounds down, because in the exact output case (decreasing price) we need to move the +/// price at least far enough to get the desired output amount, and in the exact input case +/// (increasing price) we need to move the price less in order to not send too much output. /// The formula we compute is within <1 wei of the lossless version: sqrtPX96 +- amount / liquidity /// /// ## Arguments @@ -194,7 +195,8 @@ pub fn get_next_sqrt_price_from_output( /// * `liquidity`: The amount of usable liquidity /// * `round_up`: Whether to round the amount up or down /// -/// returns: Amount of token0 required to cover a position of size liquidity between the two passed prices +/// returns: Amount of token0 required to cover a position of size liquidity between the two passed +/// prices pub fn get_amount_0_delta( mut sqrt_ratio_a_x96: U256, mut sqrt_ratio_b_x96: U256, @@ -230,7 +232,8 @@ pub fn get_amount_0_delta( /// * `liquidity`: The amount of usable liquidity /// * `round_up`: Whether to round the amount up, or down /// -/// returns: Amount of token1 required to cover a position of size liquidity between the two passed prices +/// returns: Amount of token1 required to cover a position of size liquidity between the two passed +/// prices pub fn get_amount_1_delta( mut sqrt_ratio_a_x96: U256, mut sqrt_ratio_b_x96: U256, diff --git a/src/utils/swap_math.rs b/src/utils/swap_math.rs index 4f3fb52..f3215cb 100644 --- a/src/utils/swap_math.rs +++ b/src/utils/swap_math.rs @@ -4,21 +4,26 @@ use uniswap_v3_math::error::UniswapV3MathError; /// Computes the result of swapping some amount in, or amount out, given the parameters of the swap /// -/// The fee, plus the amount in, will never exceed the amount remaining if the swap's `amountSpecified` is positive +/// The fee, plus the amount in, will never exceed the amount remaining if the swap's +/// `amountSpecified` is positive /// /// ## Arguments /// /// * `sqrt_ratio_current_x96`: The current sqrt price of the pool -/// * `sqrt_ratio_target_x96`: The price that cannot be exceeded, from which the direction of the swap is inferred +/// * `sqrt_ratio_target_x96`: The price that cannot be exceeded, from which the direction of the +/// swap is inferred /// * `liquidity`: The usable liquidity /// * `amount_remaining`: How much input or output amount is remaining to be swapped in/out /// * `fee_pips`: The fee taken from the input amount, expressed in hundredths of a bip /// /// ## Returns /// -/// * `sqrt_ratio_next_x96`: The price after swapping the amount in/out, not to exceed the price target -/// * `amount_in`: The amount to be swapped in, of either token0 or token1, based on the direction of the swap -/// * `amount_out`: The amount to be received, of either token0 or token1, based on the direction of the swap +/// * `sqrt_ratio_next_x96`: The price after swapping the amount in/out, not to exceed the price +/// target +/// * `amount_in`: The amount to be swapped in, of either token0 or token1, based on the direction +/// of the swap +/// * `amount_out`: The amount to be received, of either token0 or token1, based on the direction of +/// the swap /// * `fee_amount`: The amount of input that will be taken as a fee pub fn compute_swap_step( sqrt_ratio_current_x96: U256, diff --git a/src/utils/tick_math.rs b/src/utils/tick_math.rs index 637084b..43cea61 100644 --- a/src/utils/tick_math.rs +++ b/src/utils/tick_math.rs @@ -9,15 +9,18 @@ use uniswap_v3_math::error::UniswapV3MathError; pub use uniswap_v3_math::tick_math::{MAX_TICK, MIN_TICK}; -/// The minimum value that can be returned from `get_sqrt_ratio_at_tick`. Equivalent to `get_sqrt_ratio_at_tick(MIN_TICK)` +/// The minimum value that can be returned from `get_sqrt_ratio_at_tick`. Equivalent to +/// `get_sqrt_ratio_at_tick(MIN_TICK)` pub const MIN_SQRT_RATIO: U256 = uint!(4295128739_U256); -/// The maximum value that can be returned from `get_sqrt_ratio_at_tick`. Equivalent to `get_sqrt_ratio_at_tick(MAX_TICK)` +/// The maximum value that can be returned from `get_sqrt_ratio_at_tick`. Equivalent to +/// `get_sqrt_ratio_at_tick(MAX_TICK)` pub const MAX_SQRT_RATIO: U256 = uint!(1461446703485210103287273052203988822378723970342_U256); /// A threshold used for optimized bounds check, equals `MAX_SQRT_RATIO - MIN_SQRT_RATIO - 1` const MAX_SQRT_RATIO_MINUS_MIN_SQRT_RATIO_MINUS_ONE: U256 = uint!(1461446703485210103287273052203988822374428841602_U256); -/// Returns the sqrt ratio as a Q64.96 for the given tick. The sqrt ratio is computed as sqrt(1.0001)^tick +/// Returns the sqrt ratio as a Q64.96 for the given tick. The sqrt ratio is computed as +/// sqrt(1.0001)^tick /// /// ## Arguments /// @@ -107,7 +110,8 @@ pub fn get_sqrt_ratio_at_tick(tick: i32) -> Result { } /// Returns the tick corresponding to a given sqrt ratio, -/// s.t. get_sqrt_ratio_at_tick(tick) <= sqrt_ratio_x96 and get_sqrt_ratio_at_tick(tick + 1) > sqrt_ratio_x96 +/// s.t. get_sqrt_ratio_at_tick(tick) <= sqrt_ratio_x96 and get_sqrt_ratio_at_tick(tick + 1) > +/// sqrt_ratio_x96 /// /// ## Arguments /// @@ -115,9 +119,10 @@ pub fn get_sqrt_ratio_at_tick(tick: i32) -> Result { /// /// returns: Result pub fn get_tick_at_sqrt_ratio(sqrt_ratio_x96: U256) -> Result { - // Equivalent: if (sqrt_ratio_x96 < MIN_SQRT_RATIO || sqrt_ratio_x96 >= MAX_SQRT_RATIO) revert("R"); - // if sqrt_ratio_x96 < MIN_SQRT_RATIO, the `sub` underflows and `gt` is true - // if sqrt_ratio_x96 >= MAX_SQRT_RATIO, sqrt_ratio_x96 - MIN_SQRT_RATIO > MAX_SQRT_RATIO - MAX_SQRT_RATIO - 1 + // Equivalent: if (sqrt_ratio_x96 < MIN_SQRT_RATIO || sqrt_ratio_x96 >= MAX_SQRT_RATIO) + // revert("R"); if sqrt_ratio_x96 < MIN_SQRT_RATIO, the `sub` underflows and `gt` is true + // if sqrt_ratio_x96 >= MAX_SQRT_RATIO, sqrt_ratio_x96 - MIN_SQRT_RATIO > MAX_SQRT_RATIO - + // MAX_SQRT_RATIO - 1 if (sqrt_ratio_x96 - MIN_SQRT_RATIO) > MAX_SQRT_RATIO_MINUS_MIN_SQRT_RATIO_MINUS_ONE { return Err(UniswapV3MathError::R); } diff --git a/src/utils/types.rs b/src/utils/types.rs index 3c3559d..b3cc8bc 100644 --- a/src/utils/types.rs +++ b/src/utils/types.rs @@ -1,4 +1,5 @@ use alloy_primitives::{Address, I256, U256}; +use bigdecimal::BigDecimal; use ethers_core::types; use num_bigint::{BigInt, BigUint, Sign}; use num_traits::{Signed, ToBytes}; @@ -83,3 +84,7 @@ pub fn big_int_to_i256(x: BigInt) -> I256 { pub const fn u128_to_uint256(x: u128) -> U256 { U256::from_limbs([x as u64, (x >> 64) as u64, 0, 0]) } + +pub fn u256_to_big_decimal(x: U256) -> BigDecimal { + BigDecimal::from(u256_to_big_int(x)) +}