Skip to content

Commit

Permalink
Merge pull request #2 from shuhuiluo/tick_data_provider
Browse files Browse the repository at this point in the history
Tick data provider
  • Loading branch information
shuhuiluo authored Jan 1, 2024
2 parents 200ec9f + 1f760ac commit 845775e
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 9 deletions.
7 changes: 4 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "uniswap-v3-sdk-rs"
version = "0.4.0"
version = "0.5.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand All @@ -15,6 +15,7 @@ num-bigint = "0.4.4"
num-traits = "0.2.17"
once_cell = "1.19.0"
ruint = "1.11.1"
thiserror = "1.0.53"
uniswap-sdk-core-rust = { git = "https://github.com/malik672/uniswap-sdk-core-rust", branch = "master" }
uniswap_v3_math = "0.4.1"

Expand Down
4 changes: 4 additions & 0 deletions src/entities/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
mod pool;
mod tick;
mod tick_data_provider;
mod tick_list_data_provider;

pub use pool::Pool;
pub use tick::{Tick, TickTrait};
pub use tick_data_provider::{NoTickDataError, NoTickDataProvider, TickDataProvider};
pub use tick_list_data_provider::TickListDataProvider;
77 changes: 77 additions & 0 deletions src/entities/tick_data_provider.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use super::{Tick, TickTrait};
use anyhow::Result;
use thiserror::Error;

/// Provides information about ticks
pub trait TickDataProvider<T: TickTrait> {
/// Return information corresponding to a specific tick
///
/// # Arguments
///
/// * `tick`: The tick to load
///
/// returns: Result<impl TickTrait+Sized, Error>
///
fn get_tick(&self, tick: i32) -> Result<&T>;

/// Return the next tick that is initialized within a single word
///
/// # Arguments
///
/// * `tick`: The current tick
/// * `lte`: Whether the next tick should be lte the current tick
/// * `tick_spacing`: The tick spacing of the pool
///
/// returns: Result<(i32, bool), Error>
///
fn next_initialized_tick_within_one_word(
&self,
tick: i32,
lte: bool,
tick_spacing: i32,
) -> Result<(i32, bool)>;
}

#[derive(Error, Debug)]
#[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.
pub struct NoTickDataProvider;

impl TickDataProvider<Tick> for NoTickDataProvider {
fn get_tick(&self, _: i32) -> Result<&Tick> {
Err(NoTickDataError.into())
}

fn next_initialized_tick_within_one_word(
&self,
_: i32,
_: bool,
_: i32,
) -> Result<(i32, bool)> {
Err(NoTickDataError.into())
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_no_tick_data_provider() {
let tick_data_provider = NoTickDataProvider;
assert_eq!(
tick_data_provider.get_tick(0).unwrap_err().to_string(),
NoTickDataError.to_string()
);
assert_eq!(
tick_data_provider
.next_initialized_tick_within_one_word(0, false, 1)
.unwrap_err()
.to_string(),
NoTickDataError.to_string()
);
}
}
80 changes: 80 additions & 0 deletions src/entities/tick_list_data_provider.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use crate::{
entities::{Tick, TickDataProvider},
utils::TickList,
};
use anyhow::Result;

/// A data provider for ticks that is backed by an in-memory array of ticks.
pub struct TickListDataProvider {
ticks: Vec<Tick>,
}

impl TickListDataProvider {
pub fn new(ticks: Vec<Tick>, tick_spacing: i32) -> Self {
ticks.validate_list(tick_spacing);
Self { ticks }
}
}

impl TickDataProvider<Tick> for TickListDataProvider {
fn get_tick(&self, tick: i32) -> Result<&Tick> {
Ok(self.ticks.get_tick(tick))
}

fn next_initialized_tick_within_one_word(
&self,
tick: i32,
lte: bool,
tick_spacing: i32,
) -> Result<(i32, bool)> {
Ok(self
.ticks
.next_initialized_tick_within_one_word(tick, lte, tick_spacing))
}
}

#[cfg(test)]
mod tests {
use super::*;
use once_cell::sync::Lazy;

static PROVIDER: Lazy<TickListDataProvider> =
Lazy::new(|| TickListDataProvider::new(vec![Tick::new(-1, 1, -1), Tick::new(1, 1, 1)], 1));

#[test]
fn can_take_an_empty_list_of_ticks() {
TickListDataProvider::new(vec![], 1);
}

#[test]
#[should_panic(expected = "TICK_SPACING_NONZERO")]
fn throws_for_0_tick_spacing() {
TickListDataProvider::new(vec![], 0);
}

#[test]
#[should_panic(expected = "ZERO_NET")]
fn throws_for_uneven_tick_list() {
TickListDataProvider::new(vec![Tick::new(-1, 1, -1), Tick::new(1, 1, 2)], 1);
}

#[test]
#[should_panic(expected = "NOT_CONTAINED")]
fn throws_if_tick_not_in_list() {
PROVIDER.get_tick(0).unwrap();
}

#[test]
fn gets_the_smallest_tick_from_the_list() {
let tick = PROVIDER.get_tick(-1).unwrap();
assert_eq!(tick.liquidity_net, -1);
assert_eq!(tick.liquidity_gross, 1);
}

#[test]
fn gets_the_largest_tick_from_the_list() {
let tick = PROVIDER.get_tick(1).unwrap();
assert_eq!(tick.liquidity_net, 1);
assert_eq!(tick.liquidity_gross, 1);
}
}
File renamed without changes.
4 changes: 2 additions & 2 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ mod compute_pool_address;
mod encode_sqrt_ratio_x96;
mod full_math;
mod get_fee_growth_inside;
mod get_tokens_owed;
mod liquidity_math;
mod nearest_usable_tick;
mod position;
mod price_tick_conversions;
mod sqrt_price_math;
mod swap_math;
Expand All @@ -17,9 +17,9 @@ pub use compute_pool_address::compute_pool_address;
pub use encode_sqrt_ratio_x96::encode_sqrt_ratio_x96;
pub use full_math::*;
pub use get_fee_growth_inside::*;
pub use get_tokens_owed::get_tokens_owed;
pub use liquidity_math::add_delta;
pub use nearest_usable_tick::nearest_usable_tick;
pub use position::get_tokens_owed;
pub use price_tick_conversions::*;
pub use sqrt_price_math::*;
pub use swap_math::compute_swap_step;
Expand Down
4 changes: 1 addition & 3 deletions src/utils/tick_list.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use super::add_delta;
use crate::entities::TickTrait;

/// Utility methods for interacting with sorted lists of self
Expand Down Expand Up @@ -40,8 +39,7 @@ impl<T: TickTrait> TickList<T> for [T] {
);
assert!(self.is_sorted(), "SORTED");
assert_eq!(
self.iter()
.fold(0, |acc, x| add_delta(acc, x.liquidity_net()).unwrap()),
self.iter().fold(0, |acc, x| acc + x.liquidity_net()),
0,
"ZERO_NET"
);
Expand Down

0 comments on commit 845775e

Please sign in to comment.